{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": [],
      "collapsed_sections": [
        "v2Nsa9eoCHnJ"
      ]
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "source": [
        "Copyright 2023 Google LLC.\n",
        "\n",
        "Licensed under the Apache License, Version 2.0 (the \"License\");"
      ],
      "metadata": {
        "id": "2Pe8rUDv13WU"
      }
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "oJURSVoJ1uTL"
      },
      "outputs": [],
      "source": [
        "#@title License\n",
        "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "# Code excerpts from the earthquakes FERN model\n",
        "\n",
        "This code is shared as part of the \"__A Neural Encoder for Earthquake Rate Forecasting__\" paper.\n",
        "\n",
        "At first, is recommended to load it with [Colab](https://colab.research.google.com/), squeeze the code snippets and follow the example below.\n",
        "\n",
        "The notebook is broken down into two main sections: implementation, and an example of training the model on a fake catalog.\n",
        "\n",
        "All of the underlying libraries are common (numpy, tensorflow, keras), apart perhaps from [gin](https://github.com/google/gin-config) - a lightweight configuration framework that allows us to bind hyperparameters for functions,\n",
        "without passing them from function to function. So the main training method does\n",
        "not require to get a parameter for each of the underlying data set models."
      ],
      "metadata": {
        "id": "ikShjrom2B5D"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "# Implementation"
      ],
      "metadata": {
        "id": "v2Nsa9eoCHnJ"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "#@title Imports\n",
        "\n",
        "import abc\n",
        "import dataclasses\n",
        "import functools\n",
        "import itertools\n",
        "import enum\n",
        "import math\n",
        "import operator\n",
        "from typing import Any, MutableMapping, Callable, Iterable, Mapping, Optional, Sequence, TypeVar, Union\n",
        "\n",
        "import gin\n",
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "import pandas as pd\n",
        "import pyproj\n",
        "import tensorflow as tf\n",
        "import tqdm"
      ],
      "metadata": {
        "id": "Gs2XvgiG4YXC",
        "cellView": "form"
      },
      "execution_count": 1,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "gin.enter_interactive_mode()\n",
        "\n",
        "# A UTM projection centered around Japan. For details: https://epsg.io/3095.\n",
        "JAPAN_PROJECTION = pyproj.Proj(\n",
        "    '+proj=utm +zone=54 +ellps=bessel '\n",
        "    '+towgs84=-146.414,507.337,680.507,0,0,0,0 '\n",
        "    '+units=m +no_defs '\n",
        ")"
      ],
      "metadata": {
        "id": "nUuyoJAA83XL"
      },
      "execution_count": 2,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "#@title A simple filter for catalogs\n",
        "\n",
        "#@markdown Choosing earthquakes by location, time, magnitude.\n",
        "\n",
        "# A type of method that takes a catalog and returns a boolean mask for\n",
        "# earthquakes to keep.\n",
        "EarthquakeCriterionType = Callable[[pd.DataFrame], np.ndarray]\n",
        "\n",
        "\n",
        "def _is_in_rectangle(\n",
        "    catalog: pd.DataFrame,\n",
        "    longitude_range: tuple[float, float],\n",
        "    latitude_range: tuple[float, float],\n",
        ") -> np.ndarray:\n",
        "  \"\"\"Returns a mask indicating whether each earthquake is in a rectangle.\"\"\"\n",
        "  return (\n",
        "      (catalog.longitude < longitude_range[1])\n",
        "      & (catalog.longitude >= longitude_range[0])\n",
        "      & (catalog.latitude < latitude_range[1])\n",
        "      & (catalog.latitude >= latitude_range[0])\n",
        "  )\n",
        "\n",
        "@gin.configurable(denylist=['catalog'])\n",
        "def earthquake_criterion(\n",
        "    catalog: pd.DataFrame,\n",
        "    longitude_range: tuple[float, float],\n",
        "    latitude_range: tuple[float, float],\n",
        "    start_timestamp: int,\n",
        "    max_depth: float,\n",
        "    min_magnitude: float,\n",
        ") -> np.ndarray:\n",
        "  \"\"\"Returns a mask for earthquakes, according to common criteria.\n",
        "\n",
        "  Args:\n",
        "    catalog: The catalog of earthquakes.\n",
        "    longitude_range: The range of the longitude (x) side of the rectangle in\n",
        "      which earthquakes are kept.\n",
        "    latitude_range: The range of the latitude (y) side of the rectangle in which\n",
        "      earthquakes are kept.\n",
        "    start_timestamp: Only keep earthquakes starting with this timestamp (seconds\n",
        "      since  Epoch).\n",
        "    max_depth: Maximal depth of earthquakes to keep.\n",
        "    min_magnitude: Minimal magnitude of earthquakes to keep.\n",
        "\n",
        "  Returns:\n",
        "    A boolean numpy array, True where the corresponding earthquake in the\n",
        "    catalog matches all of the criteria above.\n",
        "  \"\"\"\n",
        "  return (\n",
        "      (catalog.depth <= max_depth)\n",
        "      & (catalog.magnitude >= min_magnitude)\n",
        "      & (catalog.time >= start_timestamp)\n",
        "      & _is_in_rectangle(catalog, longitude_range, latitude_range)\n",
        "  )\n"
      ],
      "metadata": {
        "cellView": "form",
        "id": "MG3QiDMTOg9S"
      },
      "execution_count": 3,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "#@title Dataclasses and types\n",
        "\n",
        "# A container for a list of evaluation locations per an evaluation timestamp.\n",
        "LocationsPerTime = MutableMapping[float, Sequence[tuple[float, float]]]\n",
        "\n",
        "\n",
        "@gin.configurable\n",
        "@dataclasses.dataclass(frozen=True)\n",
        "class Rectangle:\n",
        "  \"\"\"Specifies a rectangle in latitutde-longitude coordinates.\"\"\"\n",
        "  min_lng: float\n",
        "  max_lng: float\n",
        "  min_lat: float\n",
        "  max_lat: float\n",
        "\n",
        "\n",
        "@dataclasses.dataclass(frozen=True)\n",
        "class SampleSpaceTimes:\n",
        "  \"\"\"A set of evaluation locations for a given point in time.\"\"\"\n",
        "\n",
        "  history_time: float\n",
        "  lead_time: float\n",
        "  locations: Sequence[tuple[float, float]]\n",
        "\n",
        "  @property\n",
        "  def eval_time(self):\n",
        "    \"\"\"The time in the future, when we want to predict the rate.\"\"\"\n",
        "    return self.history_time + self.lead_time\n",
        "\n",
        "  @classmethod\n",
        "  def from_mapping(\n",
        "      cls, locations_per_time: LocationsPerTime\n",
        "  ) -> list['SampleSpaceTimes']:\n",
        "    \"\"\"Builds sample space times from an (old) mapping of times to locations.\"\"\"\n",
        "    all_times = np.array(sorted(locations_per_time))\n",
        "    history_times, eval_times = all_times[:-1], all_times[1:]\n",
        "    lead_times = eval_times - history_times\n",
        "    all_locations = [locations_per_time[t] for t in eval_times]\n",
        "    return [\n",
        "        SampleSpaceTimes(history_time=t, lead_time=lead, locations=locations)\n",
        "        for t, lead, locations in zip(history_times, lead_times, all_locations)\n",
        "    ]\n",
        "\n",
        "\n",
        "@dataclasses.dataclass(frozen=True)\n",
        "class EvaluationSpaceTimes:\n",
        "  \"\"\"A container for the evaluation space-time pairs.\n",
        "\n",
        "  Attributes:\n",
        "    train_space_times: A mapping from train times (in seconds since Epoch) to\n",
        "      corresponding locations (in UTM coordinates).\n",
        "    validation_space_times: A mapping from validation times (in seconds since\n",
        "      Epoch) to correspondinglocations (in UTM coordinates).\n",
        "    test_space_times: A mapping from test times (in seconds since Epoch) to\n",
        "      corresponding locations (in UTM coordinates).\n",
        "    locations_per_time: The number of location per time. This is to highlight\n",
        "      (and potentially verify) that the number is the same for every time.\n",
        "    train_start: Timestamp (in seconds since Epoch) of the start of the training\n",
        "      range.\n",
        "    validation_start: Timestamp (in seconds since Epoch) of the start of the\n",
        "      validation range (and the end of the training range).\n",
        "    test_start: Timestamp (in seconds since Epoch) of the start of the test\n",
        "      range (and the end of the validation range).\n",
        "    test_end: Timestamp (in seconds since Epoch) of the end of the test range.\n",
        "  \"\"\"\n",
        "\n",
        "  train_space_times: LocationsPerTime\n",
        "  validation_space_times: LocationsPerTime\n",
        "  test_space_times: LocationsPerTime\n",
        "  locations_per_time: int\n",
        "  train_start: float\n",
        "  validation_start: float\n",
        "  test_start: float\n",
        "  test_end: float\n",
        "\n",
        "  @classmethod\n",
        "  @gin.configurable(denylist=['cls'])\n",
        "  def init_with_earthquake_times_and_locations(\n",
        "      cls,\n",
        "      earthquake_criterion: EarthquakeCriterionType = earthquake_criterion,\n",
        "      catalog: Optional[pd.DataFrame] = None,\n",
        "      train_start: float = gin.REQUIRED,\n",
        "      validation_start: float = gin.REQUIRED,\n",
        "      test_start: float = gin.REQUIRED,\n",
        "      test_end: float = gin.REQUIRED,\n",
        "      longitude_range: tuple[float, float] = gin.REQUIRED,\n",
        "      latitude_range: tuple[float, float] = gin.REQUIRED,\n",
        "      grid_side_deg: float = gin.REQUIRED,\n",
        "      projection: pyproj.Proj = JAPAN_PROJECTION,\n",
        "  ) -> 'EvaluationSpaceTimes':\n",
        "    \"\"\"Calculates evaluation space-times that match earthquakes in a catalog.\n",
        "\n",
        "    The returned times and locations are such that for every time there is a\n",
        "    regular grid of locations. If the time is of an earthquake, one of these\n",
        "    locations will be the location of the earthquake. Otherwise, the locations\n",
        "    will be shifted randomly.\n",
        "\n",
        "    Args:\n",
        "      earthquake_criterion: A function that accepts an earthquake catalog and\n",
        "        returns a boolean index array of the same length, marking which\n",
        "        earthquakes to keep.\n",
        "      catalog: A dataframe of earthquakes. If None, the sample catalog is used.\n",
        "        The catalog should be sorted by time.\n",
        "      train_start: Timestamp (in seconds since Epoch) of the start of the\n",
        "        training range.\n",
        "      validation_start: Timestamp (in seconds since Epoch) of the start of the\n",
        "        validation range.\n",
        "      test_start: Timestamp (in seconds since Epoch) of the start of the test\n",
        "        range.\n",
        "      test_end: Timestamp (in seconds since Epoch) of the end of the test range.\n",
        "      longitude_range: The range of the longitude (x) side of the rectangle in\n",
        "        which earthquakes are kept. Allowed precision is up to 2 significant\n",
        "        digits (~1 km).\n",
        "      latitude_range: The range of the latitude (y) side of the rectangle in\n",
        "        which earthquakes are kept. Allowed precision is up to 2 significant\n",
        "        digits (~1 km).\n",
        "      grid_side_deg: Per evaluation time add evenly spaced evaluation locations,\n",
        "        with this grid size. Allowed precision is up to 2 significant digits (~1\n",
        "        km).\n",
        "      projection: Which projection to use (normally, from Lat/Lng to UTM).\n",
        "\n",
        "    Returns:\n",
        "      Evaluation space-times, that match the earthquakes in the (filtered)\n",
        "      catalog. The right edge of every range (train, validation, test) is\n",
        "      included as an evaluation time (with random locations).\n",
        "    \"\"\"\n",
        "    if (\n",
        "        np.round(grid_side_deg, 2) != grid_side_deg\n",
        "        or np.round(longitude_range[0], 2) != longitude_range[0]\n",
        "        or np.round(longitude_range[1], 2) != longitude_range[1]\n",
        "        or np.round(latitude_range[0], 2) != latitude_range[0]\n",
        "        or np.round(latitude_range[1], 2) != latitude_range[1]\n",
        "    ):\n",
        "      raise ValueError('The grid precision is up to 2 significant digits')\n",
        "    if catalog is None:\n",
        "      catalog = sample_catalog().sort_values('time')\n",
        "    else:\n",
        "      catalog = catalog.copy()\n",
        "    catalog = catalog[earthquake_criterion(catalog)]\n",
        "\n",
        "    split_edges = [\n",
        "        (train_start, validation_start),\n",
        "        (validation_start, test_start),\n",
        "        (test_start, test_end),\n",
        "    ]\n",
        "    splits = [\n",
        "        catalog[(catalog.time >= edges[0]) & (catalog.time < edges[1])]\n",
        "        for edges in split_edges\n",
        "    ]\n",
        "    pairs = [\n",
        "        dict(zip(df.time, zip(df.longitude, df.latitude))) for df in splits\n",
        "    ]\n",
        "\n",
        "    # Add the edge times.\n",
        "    rs = np.random.RandomState(0)\n",
        "    edge_times = [validation_start, test_start, test_end]\n",
        "    random_lngs = rs.uniform(\n",
        "        low=longitude_range[0], high=longitude_range[1], size=len(edge_times)\n",
        "    )\n",
        "    random_lats = rs.uniform(\n",
        "        low=latitude_range[0], high=latitude_range[1], size=len(edge_times)\n",
        "    )\n",
        "    for i, edge in enumerate(edge_times):\n",
        "      pairs[i][edge] = (random_lngs[i], random_lats[i])\n",
        "\n",
        "    # Add locations on a grid for all times.\n",
        "    n_locations = int(\n",
        "        np.round(\n",
        "            (longitude_range[1] - longitude_range[0])\n",
        "            * (latitude_range[1] - latitude_range[0])\n",
        "            / (grid_side_deg**2)\n",
        "        )\n",
        "    )\n",
        "    all_space_times = []\n",
        "    for part in pairs:\n",
        "      # The data sets expect locations in UTM coordniates, while the evaluation\n",
        "      # is done in Lat/Lng coordinates, to match external ETAS implementations.\n",
        "      all_space_times.append({})\n",
        "      for t, location in part.items():\n",
        "        grid = _grid_locations(\n",
        "            location, grid_side_deg, *longitude_range, *latitude_range\n",
        "        )\n",
        "        assert len(grid) == n_locations\n",
        "        all_space_times[-1][t] = [\n",
        "            projection(lng_lat[0], lng_lat[1]) for lng_lat in grid\n",
        "        ]\n",
        "\n",
        "    return EvaluationSpaceTimes(\n",
        "        all_space_times[0],\n",
        "        all_space_times[1],\n",
        "        all_space_times[2],\n",
        "        n_locations,\n",
        "        train_start,\n",
        "        validation_start,\n",
        "        test_start,\n",
        "        test_end,\n",
        "    )\n",
        "\n",
        "\n",
        "@dataclasses.dataclass(frozen=True)\n",
        "class FeatureData:\n",
        "  \"\"\"Contains the features that are used for training and evaluating FERN.\n",
        "\n",
        "  Class constants:\n",
        "    DELIMETER: An indicative delimeter for filenames.\n",
        "\n",
        "  Attributes:\n",
        "    train_data: Features used for training. Keyed by the name of the dataset.\n",
        "    validation_data: Features used for validation. Keyed by the name of the\n",
        "      dataset.\n",
        "    test_data: Features used for testing. Keyed by the name of the dataset.\n",
        "  \"\"\"\n",
        "\n",
        "  train_data: dict[str, np.ndarray]\n",
        "  validation_data: dict[str, np.ndarray]\n",
        "  test_data: dict[str, np.ndarray]\n",
        "\n",
        "  DELIMETER = '__'\n",
        "\n",
        "  @gin.configurable\n",
        "  def to_flat_partial(self, do_not_flatten: Sequence[str]) -> 'FeatureData':\n",
        "    \"\"\"Returns a flat version of the feature data.\n",
        "\n",
        "    Args:\n",
        "      do_not_flatten: A list of feature names that should not be completely\n",
        "        flattened.\n",
        "\n",
        "    Returns:\n",
        "      New feature data, with flattened features. If the features are of shape\n",
        "      (n_times, n_locations, x1, x2, ..., xn), the output features will have\n",
        "      either shape (n_times * n_locations, x1*x2*...*x{n-1}, xn) - if they\n",
        "      appear in the `do_not_flatten` list or shape\n",
        "      (n_times * n_locations, x1*x2*...*xn) - otherwise.\n",
        "    \"\"\"\n",
        "    new_train_data = {\n",
        "        key: reshape_features_to_2d(data)\n",
        "        for key, data in self.train_data.items()\n",
        "    }\n",
        "    new_validation_data = {\n",
        "        key: reshape_features_to_2d(data)\n",
        "        for key, data in self.validation_data.items()\n",
        "    }\n",
        "    new_test_data = {\n",
        "        key: reshape_features_to_2d(data)\n",
        "        for key, data in self.test_data.items()\n",
        "    }\n",
        "    for name in do_not_flatten:\n",
        "      new_train_data[name] = reshape_features_to_3d(self.train_data[name])\n",
        "      new_validation_data[name] = reshape_features_to_3d(\n",
        "          self.validation_data[name]\n",
        "      )\n",
        "      new_test_data[name] = reshape_features_to_3d(self.test_data[name])\n",
        "    return FeatureData(\n",
        "        train_data=new_train_data,\n",
        "        validation_data=new_validation_data,\n",
        "        test_data=new_test_data,\n",
        "    )\n"
      ],
      "metadata": {
        "cellView": "form",
        "id": "R6fmi8ZnMopu"
      },
      "execution_count": 4,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "#@title Some utility functions\n",
        "\n",
        "#@markdown 1. `earthquake_criterion` to get a subset of the catalog\n",
        "#@markdown 2. `Rectangles` - a class to work with a grid of rectangles, while\n",
        "#@markdown keeping track of the used projection\n",
        "#@markdown 3. `StandardScaler` - A modification of sklearn's StandardScaler that\n",
        "#@markdown allows to select axes\n",
        "\n",
        "\n",
        "@dataclasses.dataclass(frozen=True)\n",
        "class Rectangles:\n",
        "  \"\"\"A container for a list of a grid of rectangles, with useful methods.\n",
        "\n",
        "  Attributes:\n",
        "    rectangles: The list of rectangles.\n",
        "    side_deg: The length of the side of the rectangles of the grid (in degrees).\n",
        "    length: The number of rectangles in the grid.\n",
        "  \"\"\"\n",
        "  rectangles: Sequence[Rectangle]\n",
        "  side_deg: float\n",
        "  length: int\n",
        "\n",
        "  @classmethod\n",
        "  @gin.configurable(denylist=['cls'])\n",
        "  def init_grid(\n",
        "      cls,\n",
        "      longitude_range: tuple[float, float],\n",
        "      latitude_range: tuple[float, float],\n",
        "      side_deg: float,\n",
        "  ) -> 'Rectangles':\n",
        "    \"\"\"Calculates evenly spaced rectangles.\n",
        "\n",
        "    Args:\n",
        "      longitude_range: The range of the longitude (x) side of the rectangle in\n",
        "        which earthquakes are kept.\n",
        "      latitude_range: The range of the latitude (y) side of the rectangle in\n",
        "        which earthquakes are kept.\n",
        "      side_deg: The length of the side of the rectangles of the grid in degrees.\n",
        "\n",
        "    Returns:\n",
        "      A list of rectangles for the requested grid.\n",
        "    \"\"\"\n",
        "    if (\n",
        "        np.round(side_deg, 2) != side_deg\n",
        "        or np.round(longitude_range[0], 2) != longitude_range[0]\n",
        "        or np.round(longitude_range[1], 2) != longitude_range[1]\n",
        "        or np.round(latitude_range[0], 2) != latitude_range[0]\n",
        "        or np.round(latitude_range[1], 2) != latitude_range[1]\n",
        "    ):\n",
        "      raise ValueError('The grid precision is up to 2 significant digits')\n",
        "\n",
        "    int_side = int(np.round(side_deg * 100))\n",
        "    int_lng_range = (\n",
        "        int(np.round(longitude_range[0] * 100)),\n",
        "        int(np.round(longitude_range[1] * 100)),\n",
        "    )\n",
        "    int_lat_range = (\n",
        "        int(np.round(latitude_range[0] * 100)),\n",
        "        int(np.round(latitude_range[1] * 100)),\n",
        "    )\n",
        "\n",
        "    min_lng_points = np.arange(*int_lng_range, int_side)\n",
        "    min_lat_points = np.arange(*int_lat_range, int_side)\n",
        "\n",
        "    rectangles = [\n",
        "        Rectangle(\n",
        "            lng / 100, (lng + int_side) / 100, lat / 100, (lat + int_side) / 100\n",
        "        )\n",
        "        for lng, lat in itertools.product(min_lng_points, min_lat_points)\n",
        "    ]\n",
        "\n",
        "    return Rectangles(rectangles, side_deg, len(rectangles))\n",
        "\n",
        "  def index_of(\n",
        "      self, location: tuple[float, float], projection: pyproj.Proj\n",
        "  ) -> int:\n",
        "    \"\"\"Returns the index of the bin that contains the input location.\n",
        "\n",
        "    Args:\n",
        "      location: In UTM coordinates.\n",
        "      projection: Which projection to use (normally, from Lat/Lng to UTM).\n",
        "\n",
        "    Returns:\n",
        "      The index of the bin that contains that location.\n",
        "    \"\"\"\n",
        "    lng, lat = _utm_to_lng_lat(*location, projection)\n",
        "    for i, rectangle in enumerate(self.rectangles):\n",
        "      if rectangle.min_lng <= lng <= rectangle.max_lng:\n",
        "        if rectangle.min_lat <= lat <= rectangle.max_lat:\n",
        "          return i\n",
        "    raise ValueError(\n",
        "        f'Location {location} - ({lng}, {lat}) is not in any of the bins {self}'\n",
        "    )\n",
        "\n",
        "\n",
        "def _utm_to_lng_lat(\n",
        "    x: float, y: float, projection: pyproj.Proj\n",
        ") -> tuple[float, float]:\n",
        "  \"\"\"Converts UTM coordinates back to longitude and latitude.\"\"\"\n",
        "  lng, lat = projection(x, y, inverse=True)\n",
        "  lng_deg, lat_deg = math.floor(lng), math.floor(lat)\n",
        "  # Converting back to minutes, because then we can limit to the precision of\n",
        "  # the catalog - 2 decimal points. This helps deal with points near the\n",
        "  # boundary of rectangles.\n",
        "  lng_minutes = np.round((lng - lng_deg) * 60, 2)\n",
        "  lat_minutes = np.round((lat - lat_deg) * 60, 2)\n",
        "  return lng_deg + lng_minutes / 60, lat_deg + lat_minutes / 60\n",
        "\n",
        "\n",
        "@gin.configurable\n",
        "def init_rectangles_grid(\n",
        "    longitude_range: tuple[float, float],\n",
        "    latitude_range: tuple[float, float],\n",
        "    side_deg: float,\n",
        ") -> Rectangles:\n",
        "  \"\"\"A thin wrapper around Rectangles.init_grid, for scoped binding.\"\"\"\n",
        "  return Rectangles.init_grid(longitude_range, latitude_range, side_deg)\n",
        "\n",
        "\n",
        "def shift_locations_per_time(\n",
        "    time_to_location: LocationsPerTime, new_time: float\n",
        ") -> LocationsPerTime:\n",
        "  \"\"\"Creates a new time to locations mapping, that includes the new time.\n",
        "\n",
        "  The new time must be before all times in the mapping.\n",
        "\n",
        "  Args:\n",
        "    time_to_location: A mapping from times to lists of locations.\n",
        "    new_time: The new time to include in the mapping.\n",
        "\n",
        "  Returns:\n",
        "    A new mapping, that includes the new time, and excludes the most recent time\n",
        "    in the original mapping. The locations are shifted by 1, from each timestamp\n",
        "    to the timestamp that immediately precedes it in the original mapping (and\n",
        "    the locations of the least recent time are shifted to the new time).\n",
        "  \"\"\"\n",
        "  new_time_to_locations = {}\n",
        "  times = np.sort(np.concatenate([[new_time], list(time_to_location.keys())]))\n",
        "  assert times[0] == new_time\n",
        "  for i in range(len(times) - 1):\n",
        "    new, old = times[i], times[i + 1]\n",
        "    new_time_to_locations[new] = time_to_location[old]\n",
        "  return new_time_to_locations\n",
        "\n",
        "\n",
        "def _grid_locations(\n",
        "    location: tuple[float, float],\n",
        "    grid_side: float,\n",
        "    min_lng: float,\n",
        "    max_lng: float,\n",
        "    min_lat: float,\n",
        "    max_lat: float,\n",
        ") -> Sequence[tuple[float, float]]:\n",
        "  \"\"\"Returns an evenly spaced grid that starts at a given location.\"\"\"\n",
        "  # If the grid side is not an integer, the modulus can cause us to include the\n",
        "  # wrong edge of the rectangle, due to floating point operation precision. We\n",
        "  # fix this by limiting ourselves to 2 significant digits.\n",
        "  int_grid_side = int(np.round(grid_side * 100))\n",
        "  int_lng_range = (int(np.round(min_lng * 100)), int(np.round(max_lng * 100)))\n",
        "  int_lat_range = (int(np.round(min_lat * 100)), int(np.round(max_lat * 100)))\n",
        "  shift_lng = (location[0] * 100 - int_lng_range[0]) % int_grid_side\n",
        "  shift_lat = (location[1] * 100 - int_lat_range[0]) % int_grid_side\n",
        "  return list(\n",
        "      itertools.product(\n",
        "          (np.arange(*int_lng_range, int_grid_side) + shift_lng) / 100,\n",
        "          (np.arange(*int_lat_range, int_grid_side) + shift_lat) / 100,\n",
        "      )\n",
        "  )\n",
        "\n",
        "\n",
        "def reshape_features_to_2d(array: np.ndarray) -> np.ndarray:\n",
        "  \"\"\"Reshapes an n-dimensional feature array to 2 dimensions.\n",
        "\n",
        "  Args:\n",
        "    array: Input feature array, created by some data set; that is - it is\n",
        "      assumed to have shape (n_times, n_locations, ...).\n",
        "\n",
        "  Returns:\n",
        "    A 2d version of the feature array, where the first axis corresponds to the\n",
        "    index of the example, and the second axis corresponds to the index of the\n",
        "    feature.\n",
        "  \"\"\"\n",
        "  return array.reshape((array.shape[0] * array.shape[1], -1))\n",
        "\n",
        "\n",
        "def reshape_features_to_3d(array: np.ndarray) -> np.ndarray:\n",
        "  \"\"\"Reshapes an n-dimensional array to 3 dimensions.\n",
        "\n",
        "  Args:\n",
        "    array: Input feature array, created by some data set; that is - it is\n",
        "      assumed to have shape (n_times, n_locations, ..., n_features).\n",
        "\n",
        "  Returns:\n",
        "    A 3d version of the feature array, where the first axis corresponds to the\n",
        "    index of the example, the second axis corresponds to the index of a setup,\n",
        "    and the last axis corresponds to a feature function for that setup. This is\n",
        "    a useful representation for RNNs and CNNs.\n",
        "  \"\"\"\n",
        "  product = lambda arr: functools.reduce(operator.mul, arr, 1)\n",
        "  return array.reshape(\n",
        "      (product(array.shape[:2]), product(array.shape[2:-1]), array.shape[-1])\n",
        "  )\n",
        "\n",
        "\n",
        "class StandardScaler:\n",
        "  \"\"\"A modification of sklearn's StandardScaler that allows to select axes.\"\"\"\n",
        "\n",
        "  def __init__(self, feature_axes: Union[int, Sequence[int]] = 0):\n",
        "    \"\"\"Initializes a StandardScaler with 0 mean and standard deviation of 1.\n",
        "\n",
        "    Args:\n",
        "      feature_axes: int or tuple of ints. The axes over which mean and std are\n",
        "        to be standardized. In the original scikit implementation this is 0.\n",
        "    \"\"\"\n",
        "    self.mean = 0\n",
        "    self.std = 1\n",
        "    self.feature_axes = feature_axes\n",
        "\n",
        "  def fit(self, x: np.ndarray):\n",
        "    \"\"\"Computes the mean and std to be used for later scaling.\"\"\"\n",
        "    self.mean = x.mean(axis=self.feature_axes, keepdims=True)\n",
        "    self.std = x.std(axis=self.feature_axes, keepdims=True)\n",
        "\n",
        "  def transform(self, x: np.ndarray) -> np.ndarray:\n",
        "    \"\"\"Performs standardization by centering and scaling.\"\"\"\n",
        "    return (x - self.mean) / self._handle_zeros_in_std()\n",
        "\n",
        "  def fit_transform(self, x: np.ndarray) -> np.ndarray:\n",
        "    \"\"\"Performs both fit and transform on the input.\"\"\"\n",
        "    self.fit(x)\n",
        "    return self.transform(x)\n",
        "\n",
        "  def _handle_zeros_in_std(self) -> Union[float, np.ndarray]:\n",
        "    \"\"\"Handles case of zero std.\n",
        "\n",
        "    Returns:\n",
        "      Array/scalar of the same shape as `self.std`, with zeros replaced by ones.\n",
        "    \"\"\"\n",
        "    if np.isscalar(self.std):\n",
        "      if self.std == 0:\n",
        "        return 1\n",
        "      return self.std\n",
        "    elif isinstance(self.std, np.ndarray):\n",
        "      std = self.std.copy()\n",
        "      std[std == 0.0] = 1.0\n",
        "      return std\n",
        "    raise ValueError('Unknown std type.')\n"
      ],
      "metadata": {
        "id": "vSFtNG1s6F01",
        "cellView": "form"
      },
      "execution_count": 5,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "#@title Architectures\n",
        "\n",
        "#@markdown Some sample architecture implementations that can be passed to the\n",
        "#@markdown encoders.\n",
        "\n",
        "# A function that takes the name of the model, the size of the input, and any\n",
        "# additional arguments, and returns a Keras model with the given input size.\n",
        "ModelConstructor = Callable[[str, int], tf.keras.Model]\n",
        "\n",
        "def _cnn_1d_layers(\n",
        "    name: str,\n",
        "    input_layer: tf.keras.layers.Layer,\n",
        "    input_shape: Sequence[int],\n",
        "    cnn_filters: Sequence[int],\n",
        "    activation: str = 'relu',\n",
        "    kernel_regularization: Optional[tf.keras.regularizers.Regularizer] = None,\n",
        ") -> tf.keras.layers.Layer:\n",
        "  \"\"\"Applies a 1d CNN to an input, that represents a functions on the last axis.\n",
        "\n",
        "  Assume that the input shape is (example, setups, feature), i.e. for every\n",
        "  example (1st axis) there are several feature functions (3rd axis) that are\n",
        "  calculated for different setups (2nd axis). For example `setups` can be one of\n",
        "  the few past earthquakes, and `features` are functions that are calculated on\n",
        "  each earthquake.\n",
        "  This model starts with a few Conv layers, that are repeatedly applied to the\n",
        "  entire last axis (thus, learning some combination of the features, that is\n",
        "  shared between the different setups).\n",
        "\n",
        "  Args:\n",
        "    name: An identifier of the model.\n",
        "    input_layer: The input layer.\n",
        "    input_shape: The shape of the input layer. Expected to be 2-dimensional.\n",
        "    cnn_filters: The number of filters per layer. The shape of every filter is\n",
        "      equal to the number of filters in the previous layer (always taking the\n",
        "      entire last axis).\n",
        "    activation: The Keras activation function to use.\n",
        "    kernel_regularization: Regularizer function.\n",
        "\n",
        "  Returns:\n",
        "    The output layer after the CNN layers are applied.\n",
        "  \"\"\"\n",
        "  kernel_shape = (1, input_shape[-1])\n",
        "  output_layer = tf.keras.layers.Reshape((*input_shape, 1))(input_layer)\n",
        "  for i, n_filters in enumerate(cnn_filters):\n",
        "    output_layer = tf.keras.layers.Conv2D(\n",
        "        name=f'{name}_{i}_cnn',\n",
        "        dtype='float64',\n",
        "        filters=n_filters,\n",
        "        kernel_size=kernel_shape,\n",
        "        activation=activation,\n",
        "        kernel_regularizer=kernel_regularization,\n",
        "    )(output_layer)\n",
        "    kernel_shape = (1, n_filters)\n",
        "    # Swap the 'channels' axis to the last feature axis.\n",
        "    output_layer = tf.keras.layers.Permute((1, 3, 2), dtype='float64')(\n",
        "        output_layer\n",
        "    )\n",
        "\n",
        "  return output_layer\n",
        "\n",
        "\n",
        "@gin.configurable\n",
        "def order_invariant_cnn_model(\n",
        "    name: str,\n",
        "    input_shape: Sequence[int],\n",
        "    cnn_filters: Sequence[int],\n",
        "    activation: str = 'relu',\n",
        "    kernel_regularization: Optional[tf.keras.regularizers.Regularizer] = None,\n",
        ") -> tf.keras.Model:\n",
        "  \"\"\"Prepares a CNN model that represents a function on the set of examples.\n",
        "\n",
        "  Args:\n",
        "    name: An identifier of the model.\n",
        "    input_shape: The shape of the input layer. Expected to be 2-dimensional.\n",
        "    cnn_filters: The number of filters per layer. The shape of every filter is\n",
        "      equal to the number of filters in the previous layer (always taking the\n",
        "      entire last axis).\n",
        "    activation: The Keras activation function to use.\n",
        "    kernel_regularization: Regularizer function.\n",
        "\n",
        "  Returns:\n",
        "    A CNN followed by a sum (thus, being invariant to the order of examples).\n",
        "  \"\"\"\n",
        "  input_layer = tf.keras.layers.Input(\n",
        "      shape=input_shape, name=name, dtype='float64'\n",
        "  )\n",
        "\n",
        "  output_layer = _cnn_1d_layers(\n",
        "      name,\n",
        "      input_layer,\n",
        "      input_shape,\n",
        "      cnn_filters,\n",
        "      activation,\n",
        "      kernel_regularization,\n",
        "  )\n",
        "\n",
        "  output_layer = tf.keras.layers.Lambda(\n",
        "      lambda x: tf.keras.backend.sum(x, axis=1)\n",
        "  )(output_layer)\n",
        "  output_layer = tf.keras.layers.Flatten()(output_layer)\n",
        "\n",
        "  return tf.keras.models.Model(inputs=input_layer, outputs=output_layer)\n",
        "\n",
        "\n",
        "@gin.configurable\n",
        "def cnn_1d_model(\n",
        "    name: str,\n",
        "    input_shape: Sequence[int],\n",
        "    cnn_filters: Sequence[int],\n",
        "    dense_units: Sequence[int],\n",
        "    activation: str = 'relu',\n",
        "    kernel_regularization: Optional[tf.keras.regularizers.Regularizer] = None,\n",
        ") -> tf.keras.Model:\n",
        "  \"\"\"Prepares a CNN model that represents a functions on the last axis.\n",
        "\n",
        "  Args:\n",
        "    name: An identifier of the model.\n",
        "    input_shape: The shape of the input layer. Expected to be 2-dimensional.\n",
        "    cnn_filters: The number of filters per layer. The shape of every filter is\n",
        "      equal to the number of filters in the previous layer (always taking the\n",
        "      entire last axis).\n",
        "    dense_units: A list of sizes of the hidden and output layers.\n",
        "    activation: The Keras activation function to use.\n",
        "    kernel_regularization: Regularizer function.\n",
        "\n",
        "  Returns:\n",
        "    A CNN followed by a fully connected model.\n",
        "  \"\"\"\n",
        "  input_layer = tf.keras.layers.Input(\n",
        "      shape=input_shape, name=name, dtype='float64'\n",
        "  )\n",
        "\n",
        "  output_layer = _cnn_1d_layers(\n",
        "      name,\n",
        "      input_layer,\n",
        "      input_shape,\n",
        "      cnn_filters,\n",
        "      activation,\n",
        "      kernel_regularization,\n",
        "  )\n",
        "\n",
        "  output_layer = tf.keras.layers.Flatten()(output_layer)\n",
        "\n",
        "  for i, units in enumerate(dense_units):\n",
        "    output_layer = tf.keras.layers.Dense(\n",
        "        units=units,\n",
        "        name=f'{name}_{i}_dense',\n",
        "        dtype='float64',\n",
        "        activation=activation,\n",
        "        kernel_regularizer=kernel_regularization,\n",
        "    )(output_layer)\n",
        "  return tf.keras.models.Model(inputs=input_layer, outputs=output_layer)\n",
        "\n",
        "\n",
        "@gin.configurable\n",
        "def fully_connected_model(\n",
        "    name: str,\n",
        "    input_size: int,\n",
        "    layer_sizes: Sequence[int],\n",
        "    activation: str = 'relu',\n",
        "    kernel_regularization: Optional[tf.keras.regularizers.Regularizer] = None,\n",
        ") -> tf.keras.Model:\n",
        "  \"\"\"Generates a keras model of stacked fully connected layers.\n",
        "\n",
        "  Args:\n",
        "    name: An identifier of the model.\n",
        "    input_size: The number of units in the input layer.\n",
        "    layer_sizes: A list of sizes of the hidden and output layers.\n",
        "    activation: The Keras activation function to use.\n",
        "    kernel_regularization: Regularizer function.\n",
        "\n",
        "  Returns:\n",
        "    A fully connecteed model.\n",
        "  \"\"\"\n",
        "  input_layer = tf.keras.layers.Input(\n",
        "      shape=(input_size,), name=name, dtype='float64'\n",
        "  )\n",
        "  output_layer = input_layer\n",
        "  for i, layer_size in enumerate(layer_sizes):\n",
        "    output_layer = tf.keras.layers.Dense(\n",
        "        layer_size,\n",
        "        kernel_initializer=tf.keras.initializers.glorot_normal(),\n",
        "        kernel_regularizer=kernel_regularization,\n",
        "        activation=activation,\n",
        "        name=f'{name}_dense_{i}',\n",
        "        dtype='float64',\n",
        "    )(output_layer)\n",
        "  return tf.keras.models.Model(inputs=input_layer, outputs=output_layer)\n",
        "\n",
        "\n",
        "@gin.configurable\n",
        "def identity_model(model_name: str, input_size: int) -> tf.keras.Model:\n",
        "  \"\"\"Prepares a model that just outputs the input.\"\"\"\n",
        "  return tf.keras.models.Sequential([\n",
        "      tf.keras.layers.InputLayer(\n",
        "          input_shape=(input_size,), name=model_name, dtype='float64'\n",
        "      ),\n",
        "  ])"
      ],
      "metadata": {
        "cellView": "form",
        "id": "Co_HglY64d4w"
      },
      "execution_count": 6,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "#@title Targets\n",
        "\n",
        "#@markdown Methods to get the \"target\" earthquakes, in some sense setting our\n",
        "#@markdown labels.\n",
        "\n",
        "@gin.configurable\n",
        "def target_earthquakes(\n",
        "    catalog: pd.DataFrame,\n",
        "    earthquake_criterion: EarthquakeCriterionType = earthquake_criterion,\n",
        ") -> pd.DataFrame:\n",
        "  \"\"\"Returns a catalog of earthquakes that we want to calculate hazards for.\n",
        "\n",
        "  Args:\n",
        "    catalog: A dataframe of earthquakes.\n",
        "    earthquake_criterion: A function that accepts an earthquake catalog and\n",
        "      returns a boolean index array of the same length, marking which\n",
        "      earthquakes to keep.\n",
        "  \"\"\"\n",
        "  catalog = catalog.copy()\n",
        "  return catalog[earthquake_criterion(catalog)]\n",
        "\n",
        "\n",
        "def earthquakes_mask_for_space_times(\n",
        "    timestamp_to_locations: LocationsPerTime,\n",
        "    tolerance_meters: float = 0.1,\n",
        "    tolerance_seconds: float = 0.01,\n",
        ") -> np.ndarray:\n",
        "  \"\"\"Calculates which space-times match target earthquakes.\n",
        "\n",
        "  Args:\n",
        "    timestamp_to_locations:  A mapping from times (in seconds since Epoch) to\n",
        "      corresponding locations (in UTM coordinates), equal number of locations\n",
        "      per timestamp.\n",
        "    tolerance_meters: How near to an earthquake in the catalog the location must\n",
        "      be, in both x and y coordinates.\n",
        "    tolerance_seconds: How near to an earthquake in the catalog the location\n",
        "      must be in the time coordinate.\n",
        "\n",
        "  Returns:\n",
        "    A binary array that indicates which space-time pairs are of earthquakes.\n",
        "    The array has two dimensions - (time, location). The array is sorted in\n",
        "    time.\n",
        "  \"\"\"\n",
        "  catalog = target_earthquakes()\n",
        "  n_locations = len(next(iter(timestamp_to_locations.values())))\n",
        "  result = np.zeros((len(timestamp_to_locations), n_locations))\n",
        "\n",
        "  assert np.all(np.diff(catalog.time.values) > 0)\n",
        "\n",
        "  timestamps = np.array(sorted(timestamp_to_locations))\n",
        "  time_index_from = np.searchsorted(\n",
        "      catalog.time.values, timestamps - tolerance_seconds, side='left'\n",
        "  )\n",
        "  time_index_to = np.searchsorted(\n",
        "      catalog.time.values, timestamps + tolerance_seconds, side='right'\n",
        "  )\n",
        "\n",
        "  # In general they may be 2 earthquakes less than `tolerance_seconds` apart,\n",
        "  # but it does not happen in our catalog. This assert will remind us to fix\n",
        "  # this method if it will ever be the case.\n",
        "  assert np.all(time_index_to - time_index_from) <= 1\n",
        "\n",
        "  for i, timestamp in enumerate(timestamps):\n",
        "    from_index, to_index = time_index_from[i], time_index_to[i]\n",
        "    if from_index == to_index:\n",
        "      continue\n",
        "    x, y = catalog.x_utm.iloc[from_index], catalog.y_utm.iloc[from_index]\n",
        "    for j, location in enumerate(timestamp_to_locations[timestamp]):\n",
        "      if (\n",
        "          abs(x - location[0]) <= tolerance_meters\n",
        "          and abs(y - location[1]) <= tolerance_meters\n",
        "      ):\n",
        "        result[i, j] = 1\n",
        "        break\n",
        "  return result\n"
      ],
      "metadata": {
        "id": "AT4biQk79W31",
        "cellView": "form"
      },
      "execution_count": 7,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "#@title Data sets\n",
        "\n",
        "\"\"\"Classes encapsulating different data sets used for FERN.\n",
        "\n",
        "Every class here represents a different way to encode data for FERN.\n",
        "Every class is responsible for the feature engineering of its data set.\n",
        "Additionally, every class creates a keras model that encodes these features.\n",
        "Downstream, FERN combines all of these models into one.\n",
        "\n",
        "DeltaTimeDataSet and EarthquakesMaskDataSet are special data sets that are used\n",
        "to construct the FERN model, and do not have their own encoding models.\n",
        "All of the other data sets are optional.\n",
        "\"\"\"\n",
        "\n",
        "\n",
        "@gin.constants_from_enum\n",
        "class DataSetType(enum.Enum):\n",
        "  \"\"\"Type of the data source.\"\"\"\n",
        "  DELTA_TIME = 1\n",
        "  EARTHQUAKES_MASK = 2\n",
        "  GREATEST_EARTHQUAKES = 3\n",
        "  LOCATION = 4\n",
        "  LOCATION_COORDINATES = 5\n",
        "  RECENT_EARTHQUAKES = 6\n",
        "  SEISMICITY_RATE = 7\n",
        "\n",
        "\n",
        "# A type for functions that extract features from the catalog.\n",
        "# The inputs are (1) the catalog, with n earthquakes, (2) a timestamp, (3) and\n",
        "# (4) arrays of the x and y coordinates (respectively) of a list of m locations.\n",
        "# The output is a 2d array of shape (m, n), holding the feature that corresponds\n",
        "# to each location and earthquake.\n",
        "CatalogFeature = Callable[\n",
        "    [pd.DataFrame, int, np.ndarray, np.ndarray], np.ndarray\n",
        "]\n",
        "\n",
        "# A type for functions that extract features from seismicity rates.\n",
        "# The inputs are (1) an array of shape (N, D), containing at index [i, j] the\n",
        "# number of earthquakes with magnitude at least M in the L seconds before T at\n",
        "# distance at most distances[j] from locations[i], (2) the D distances, (3) the\n",
        "# magnitude M, (4) the lookback threshold D.\n",
        "# The output is a 1d array of size N, holding the feature that corresponds to\n",
        "# each location.\n",
        "SeismicityRateFeature = Callable[\n",
        "    [np.ndarray, np.ndarray, float, float], np.ndarray\n",
        "]\n",
        "\n",
        "\n",
        "def _repeat(array: np.ndarray, times: int) -> np.ndarray:\n",
        "  \"\"\"Repeats an input array along the 1st dimension.\"\"\"\n",
        "  return array.reshape(1, -1).repeat(times, axis=0)\n",
        "\n",
        "\n",
        "def _distances(\n",
        "    catalog: pd.DataFrame, x_coordinates: np.ndarray, y_coordinates: np.ndarray\n",
        ") -> np.ndarray:\n",
        "  \"\"\"Calculates the distance between every earthquake and every coordinate.\"\"\"\n",
        "  return (\n",
        "      np.subtract.outer(x_coordinates, catalog.x_utm.values) ** 2\n",
        "      + np.subtract.outer(y_coordinates, catalog.y_utm.values) ** 2\n",
        "  ) ** 0.5\n",
        "\n",
        "\n",
        "DEFAULT_CATALOG_FUNCTIONS = (\n",
        "    # 1 over the distance between earthquakes and evaluation locations.\n",
        "    lambda df, t, xs, ys: 1 / (_distances(df, xs, ys) + 1e-3),\n",
        "    # Log of the distance between earthquakes and evaluation locations.\n",
        "    lambda df, t, xs, ys: np.log(_distances(df, xs, ys) + 1e-3),\n",
        "    # Relative location of the earthquake.\n",
        "    lambda df, t, xs, ys: np.subtract.outer(xs, df.x_utm.values),\n",
        "    lambda df, t, xs, ys: np.subtract.outer(ys, df.y_utm.values),\n",
        "    # The exponent of the magnitude of the earthqukes (a.k.a energy).\n",
        "    lambda df, t, xs, ys: _repeat(np.exp(df.magnitude.values), xs.size),\n",
        "    lambda df, t, xs, ys: _repeat(1 / np.exp(df.magnitude.values), xs.size),\n",
        "    # The depth of the earthqukes.\n",
        "    lambda df, t, xs, ys: _repeat(np.log(1e-3 + df.depth.values), xs.size),\n",
        "    lambda df, t, xs, ys: _repeat(df.depth.values, xs.size),\n",
        "    # The log of the time elapsed since each earthquake.\n",
        "    lambda df, t, xs, ys: _repeat(np.log(t + 1e-3 - df.time.values), xs.size),\n",
        "    # 1 over the time elapsed since each earthquake.\n",
        "    lambda df, t, xs, ys: _repeat(1 / (t + 1e-3 - df.time.values), xs.size),\n",
        ")\n",
        "\n",
        "DEFAULT_SEISMICITY_RATE_FUNCTIONS = (\n",
        "    lambda n, distances, mag, lookback: n,\n",
        "    lambda n, distances, mag, lookback: np.exp(mag),\n",
        "    lambda n, distances, mag, lookback: 1 / np.exp(mag),\n",
        "    lambda n, distances, mag, lookback: 1 / lookback,\n",
        "    lambda n, distances, mag, lookback: np.log(lookback),\n",
        "    lambda n, distances, mag, lookback: 1 / distances,\n",
        "    lambda n, distances, mag, lookback: np.log(distances),\n",
        ")\n",
        "\n",
        "\n",
        "class BaseDataSet(abc.ABC):\n",
        "  \"\"\"Base class for datasets.\n",
        "\n",
        "  Attributes:\n",
        "    type: A unique identifier for the data set.\n",
        "    name: A name for the dataset, to be used downstream by FERN.\n",
        "    scaler: An instance of StandardScaler, used to normalize features. By\n",
        "      default, when normalizing, we want the distribution of a feature over all\n",
        "      timestamps and locations to be N(0, 1).\n",
        "  \"\"\"\n",
        "\n",
        "  def __init__(self, dataset_type: DataSetType, name: str):\n",
        "    \"\"\"Initializes a BaseDataSet.\n",
        "\n",
        "    Args:\n",
        "      dataset_type: A unique identifier for the data set.\n",
        "      name: A name for the dataset, to be used downstream by FERN.\n",
        "    \"\"\"\n",
        "    self.type = dataset_type\n",
        "    self.name = name\n",
        "    self.scaler = StandardScaler(feature_axes=(0, 1))\n",
        "\n",
        "  @abc.abstractmethod\n",
        "  def prepare_features(\n",
        "      self, space_times: LocationsPerTime\n",
        "  ) -> np.ndarray:\n",
        "    \"\"\"Prepares the features of the dataset.\n",
        "\n",
        "    Args:\n",
        "      space_times: Times and locations at which to calculate the features. It is\n",
        "        expected to have the same number of locations per timestamp. Note that\n",
        "        some datasets may expect the timestamp to be after and some before the\n",
        "        lead time (=delta_time).\n",
        "\n",
        "    Returns:\n",
        "      An n-dimensional array of features. The first dimension is the time\n",
        "      dimension, i.e. the length of the first axis should be `len(space_times)`.\n",
        "      The second dimension is the space dimension, i.e. the length of the second\n",
        "      axis should be the length of any value in `space_times`.\n",
        "      The features at index [i,j,:] will always be for the i-th timestamp, when\n",
        "      the timestamps are sorted, and the j-th location in the order specified in\n",
        "      `space_times[t]`.\n",
        "    \"\"\"\n",
        "\n",
        "  @abc.abstractmethod\n",
        "  def generate_model(self) -> tf.keras.Model:\n",
        "    \"\"\"Generates a dataset-specific keras model to be integrated in FERN.\"\"\"\n",
        "\n",
        "\n",
        "class DeltaTimeDataSet(BaseDataSet):\n",
        "  \"\"\"Data set with one feature: the lead time of the example.\"\"\"\n",
        "\n",
        "  def __init__(self, name: str = 'delta_time'):\n",
        "    \"\"\"Initializes the data set.\"\"\"\n",
        "    super().__init__(dataset_type=DataSetType.DELTA_TIME, name=name)\n",
        "\n",
        "  def prepare_features(self, space_times: LocationsPerTime):\n",
        "    \"\"\"Prepares the features of the dataset.\n",
        "\n",
        "    Args:\n",
        "      space_times: Times and locations at which to calculate the features. Only\n",
        "        uses the times.\n",
        "\n",
        "    Returns:\n",
        "      A 3-dimensional array of shape (len(space_times) - 1, len(locations), 1),\n",
        "      (where 'locations' is the number of locations for every timestamp) holding\n",
        "      the sizes of the time bins.\n",
        "    \"\"\"\n",
        "    delta_time = np.diff(sorted(space_times.keys()))\n",
        "    n_locations = len(next(iter(space_times.values())))\n",
        "    assert np.all(delta_time > 0)\n",
        "    return np.repeat(\n",
        "        delta_time.reshape((len(space_times) - 1, 1, 1)), n_locations, axis=1\n",
        "    )\n",
        "\n",
        "  def generate_model(self) -> tf.keras.Model:\n",
        "    \"\"\"Prepares the keras model. In this case, it should not be used.\"\"\"\n",
        "    raise NotImplementedError(\n",
        "        'This feature should never have an encoding model directly.'\n",
        "    )\n",
        "\n",
        "\n",
        "class EarthquakesMaskDataSet(BaseDataSet):\n",
        "  \"\"\"Data set that indicates whether the space-time bin has an earthquake.\"\"\"\n",
        "\n",
        "  def __init__(self, name: str = 'earthquakes_mask'):\n",
        "    \"\"\"Initializes the data set.\"\"\"\n",
        "    super().__init__(dataset_type=DataSetType.EARTHQUAKES_MASK, name=name)\n",
        "\n",
        "  def prepare_features(self, space_times: LocationsPerTime):\n",
        "    \"\"\"Prepares the features of the dataset.\n",
        "\n",
        "    Args:\n",
        "      space_times: Times and locations at which to calculate the features. It is\n",
        "        expected to have the same number of locations per timestamp. Expects the\n",
        "        times to be after the lead time, so that the mask marks every space-time\n",
        "        at the future (prediction) time, not at the past (history) time.\n",
        "\n",
        "    Returns:\n",
        "      A 3-dimensional array of shape (len(space_times), len(locations, 1)),\n",
        "      (where 'locations' is the number of locations for every timestamp) holding\n",
        "      an indicator whether the space-time has an earthquake.\n",
        "    \"\"\"\n",
        "    mask = earthquakes_mask_for_space_times(space_times)\n",
        "    return mask.reshape((mask.shape[0], mask.shape[1], 1))\n",
        "\n",
        "  def generate_model(self) -> tf.keras.Model:\n",
        "    \"\"\"Prepares the keras model. In this case, it should not be used.\"\"\"\n",
        "    raise NotImplementedError(\n",
        "        'This feature should never have an encoding model directly.'\n",
        "    )\n",
        "\n",
        "\n",
        "def _mock_earthquake(catalog: pd.DataFrame) -> pd.DataFrame:\n",
        "  \"\"\"Creates a tiny earthquake in the mean location of the catalog.\"\"\"\n",
        "  if len(catalog) == 0:\n",
        "    return pd.DataFrame({\n",
        "        'time': [0],\n",
        "        'x_utm': [0],\n",
        "        'y_utm': [0],\n",
        "        'depth': [100],\n",
        "        'magnitude': [-3],\n",
        "    })\n",
        "  return pd.DataFrame({\n",
        "      'time': [catalog.time.min()],\n",
        "      'x_utm': [catalog.x_utm.mean()],\n",
        "      'y_utm': [catalog.y_utm.mean()],\n",
        "      'depth': [catalog.depth.mean()],\n",
        "      'magnitude': [-3],\n",
        "  })\n",
        "\n",
        "\n",
        "def _catalog_features_limited_earthquakes(\n",
        "    catalog: pd.DataFrame,\n",
        "    sort_by: str,\n",
        "    space_times: LocationsPerTime,\n",
        "    n_seconds: int,\n",
        "    max_earthquakes: int,\n",
        "    feature_functions: Sequence[CatalogFeature],\n",
        ") -> np.ndarray:\n",
        "  \"\"\"Generates a raw feature numpy array for a limited number of earthquakes.\n",
        "\n",
        "  Selects at most `max_earthquakes` in the past `n_seconds`, sorted by\n",
        "  `sort_by`, and then calculates feature functions on the resulting entries.\n",
        "\n",
        "  Args:\n",
        "    catalog: Catalog of earthquakes.\n",
        "    sort_by: Column name to sort earthquakes by, before choosing the top few.\n",
        "      The sort is descending (so we take the most recent earthquakes if we sort\n",
        "      by time, or the greatest magnitude earthquakes if we sort by magnitude).\n",
        "    space_times: Times and locations at which to calculate the features. It is\n",
        "      expected to have the same number of locations per timestamp.\n",
        "    n_seconds: Number of seconds in the past to search for the earthquakes.\n",
        "    max_earthquakes: Limit for the number of earthquakes to keep. If there are\n",
        "      less than `max_earthquakes` in the time range, mock earthquakes with tiny\n",
        "      magnitudes will be added.\n",
        "    feature_functions: Functions for extracting features from the catalog.\n",
        "\n",
        "  Returns:\n",
        "    Numpy array of earthquake features. The first axis corresponds to\n",
        "    timestamps, the second to locations, the third to an earthquake (sorted by\n",
        "    `sort_by`, a total of `max_earthquakes`) and the fourth to\n",
        "    `feature_functions`.\n",
        "  \"\"\"\n",
        "  timestamps = np.array(sorted(space_times.keys()))\n",
        "  n_locations = len(next(iter(space_times.values())))\n",
        "  # For each evaluation time, find the index of the first earthquake after it,\n",
        "  # and the index of the last earthquake that fits in the time range.\n",
        "  first_earthquakes_indices = np.searchsorted(\n",
        "      catalog.time, timestamps, side='right'\n",
        "  )\n",
        "  last_earthquake_indices = np.searchsorted(\n",
        "      catalog.time, timestamps - n_seconds, side='left'\n",
        "  )\n",
        "\n",
        "  features = np.empty(\n",
        "      (timestamps.size, n_locations, max_earthquakes, len(feature_functions))\n",
        "  )\n",
        "  for i, timestamp in enumerate(timestamps):\n",
        "    first_earthquake_index = first_earthquakes_indices[i]\n",
        "    last_earthquake_index = last_earthquake_indices[i]\n",
        "    earthquake_indices = slice(last_earthquake_index, first_earthquake_index)\n",
        "    sub_catalog = (\n",
        "        catalog.iloc[earthquake_indices]\n",
        "        .sort_values(sort_by, ascending=False)\n",
        "        .head(max_earthquakes)\n",
        "        .copy()\n",
        "    )\n",
        "    # Fill with default values, so that the length will always be the same.\n",
        "    to_append = _mock_earthquake(sub_catalog)\n",
        "    for _ in range(len(sub_catalog), max_earthquakes):\n",
        "      sub_catalog = pd.concat([sub_catalog, to_append])\n",
        "\n",
        "    xs = np.array([location[0] for location in space_times[timestamp]])\n",
        "    ys = np.array([location[1] for location in space_times[timestamp]])\n",
        "    for k, function in enumerate(feature_functions):\n",
        "      features[i, :, :, k] = function(sub_catalog, timestamp, xs, ys)\n",
        "  return features\n",
        "\n",
        "\n",
        "class CatalogDataSet(BaseDataSet, abc.ABC):\n",
        "  \"\"\"Abstract data set based on the earthquakes catalog.\"\"\"\n",
        "\n",
        "  def __init__(\n",
        "      self,\n",
        "      dataset_type: DataSetType,\n",
        "      name: str,\n",
        "      earthquake_criterion: EarthquakeCriterionType = earthquake_criterion,\n",
        "      catalog: Optional[pd.DataFrame] = gin.REQUIRED,\n",
        "  ):\n",
        "    \"\"\"Initializes the data set.\n",
        "\n",
        "    Args:\n",
        "      dataset_type: A unique identifier for the data set.\n",
        "      name: A name for the dataset, to be used downstream by FERN.\n",
        "      earthquake_criterion: A function that accepts an earthquake catalog and\n",
        "        returns a boolean index array of the same length, marking which\n",
        "        earthquakes to keep.\n",
        "      catalog: A dataframe of earthquakes. If None, the sample catalog is used.\n",
        "        The catalog should be sorted by time.\n",
        "    \"\"\"\n",
        "    super().__init__(dataset_type=dataset_type, name=name)\n",
        "\n",
        "    self._catalog = catalog.copy()\n",
        "    if self._catalog.time.diff().min() < 0:\n",
        "      raise ValueError('Earthquake catalog should be sorted by time.')\n",
        "\n",
        "    self._catalog = self._catalog[earthquake_criterion(self._catalog)]\n",
        "\n",
        "\n",
        "@gin.configurable\n",
        "class RecentEarthquakesDataSet(CatalogDataSet):\n",
        "  \"\"\"Data set containing data about the recent earthquakes, sorted by time.\"\"\"\n",
        "\n",
        "  def __init__(\n",
        "      self,\n",
        "      earthquake_criterion: EarthquakeCriterionType = earthquake_criterion,\n",
        "      catalog: Optional[pd.DataFrame] = gin.REQUIRED,\n",
        "      name: str = 'earthquakes',\n",
        "  ):\n",
        "    \"\"\"Initializes the data set. See CatalogDataSet.\"\"\"\n",
        "    super().__init__(\n",
        "        dataset_type=DataSetType.RECENT_EARTHQUAKES,\n",
        "        name=name,\n",
        "        earthquake_criterion=earthquake_criterion,\n",
        "        catalog=catalog,\n",
        "    )\n",
        "\n",
        "    self.scaler = StandardScaler(feature_axes=(0, 1, 2))\n",
        "\n",
        "  @gin.configurable(\n",
        "      'RecentEarthquakesDataSet.prepare_features',\n",
        "      allowlist=['n_seconds', 'max_earthquakes'],\n",
        "  )\n",
        "  def prepare_features(\n",
        "      self,\n",
        "      space_times: LocationsPerTime,\n",
        "      n_seconds: int,\n",
        "      max_earthquakes: int,\n",
        "      feature_functions: Sequence[CatalogFeature] = DEFAULT_CATALOG_FUNCTIONS,\n",
        "  ):\n",
        "    \"\"\"Generates a raw feature numpy array.\n",
        "\n",
        "    Args:\n",
        "      space_times: Times and locations at which to calculate the features. It is\n",
        "        expected to have the same number of locations per timestamp.\n",
        "      n_seconds: Number of seconds in the past to search for the past\n",
        "        earthquakes.\n",
        "      max_earthquakes: Limit for the number of earthquakes to keep. If there are\n",
        "        less than `max_earthquakes` in the time range, mock earthquakes with\n",
        "        tiny magnitudes will be added.\n",
        "      feature_functions: Functions for extracting features from the catalog.\n",
        "\n",
        "    Returns:\n",
        "      Numpy array of earthquake features. The first axis corresponds to\n",
        "      timestamps, the second to locations, the third to an earthquake (sorted by\n",
        "      time, a total of `max_earthquakes`) and the fourth to `feature_functions`.\n",
        "    \"\"\"\n",
        "    return _catalog_features_limited_earthquakes(\n",
        "        self._catalog,\n",
        "        'time',\n",
        "        space_times,\n",
        "        n_seconds,\n",
        "        max_earthquakes,\n",
        "        feature_functions,\n",
        "    )\n",
        "\n",
        "  @gin.configurable('RecentEarthquakesDataSet.generate_model')\n",
        "  def generate_model(\n",
        "      self,\n",
        "      input_size: int,\n",
        "      model_constructor: ModelConstructor = fully_connected_model,\n",
        "  ) -> tf.keras.Model:\n",
        "    \"\"\"Generates a model with the model constructor, and given input size.\n",
        "\n",
        "    Args:\n",
        "      input_size: The number of features in the input.\n",
        "      model_constructor: A method that creates a model.\n",
        "\n",
        "    Returns:\n",
        "      A model, provided by the model constructor.\n",
        "    \"\"\"\n",
        "    return model_constructor(self.name, input_size)\n",
        "\n",
        "\n",
        "def _num_in_square(\n",
        "    square_xs_from: np.ndarray,\n",
        "    square_ys_from: np.ndarray,\n",
        "    square_xs_to: np.ndarray,\n",
        "    square_ys_to: np.ndarray,\n",
        "    x_coordinates: np.ndarray,\n",
        "    y_coordinates: np.ndarray,\n",
        ") -> np.ndarray:\n",
        "  \"\"\"Returns the number of coordinates in each of the input sqaures.\n",
        "\n",
        "  The input coordinates for the squares are assumed to have shape\n",
        "    (n_squares, n_distances).\n",
        "\n",
        "  Args:\n",
        "    square_xs_from: The left x coordinates of the of the squares.\n",
        "    square_ys_from: The bottom y coordinates of the of the squares.\n",
        "    square_xs_to: The right x coordinates of the of the squares.\n",
        "    square_ys_to: The top y coordinates of the of the squares.\n",
        "    x_coordinates: The x coordinates of the locations.\n",
        "    y_coordinates: The y coordinates of the locations.\n",
        "\n",
        "  Returns:\n",
        "    A 2D array, where the [i,j]-th item holds the number of squares with the\n",
        "    j-th side length that contain the i-th location.\n",
        "  \"\"\"\n",
        "  return np.sum(\n",
        "      np.greater_equal.outer(x_coordinates, square_xs_from)\n",
        "      & np.less_equal.outer(x_coordinates, square_xs_to)\n",
        "      & np.greater_equal.outer(y_coordinates, square_ys_from)\n",
        "      & np.less_equal.outer(y_coordinates, square_ys_to),\n",
        "      axis=1,\n",
        "  )\n",
        "\n",
        "\n",
        "@gin.configurable\n",
        "class SeismicityRateDataSet(CatalogDataSet):\n",
        "  \"\"\"Data set containing the rates of earthquakes in the area.\"\"\"\n",
        "\n",
        "  def __init__(\n",
        "      self,\n",
        "      earthquake_criterion: EarthquakeCriterionType = earthquake_criterion,\n",
        "      catalog: Optional[pd.DataFrame] = gin.REQUIRED,\n",
        "      name: str = 'seismicity',\n",
        "  ):\n",
        "    \"\"\"Initializes the data set. See CatalogDataSet.\"\"\"\n",
        "    super().__init__(\n",
        "        dataset_type=DataSetType.SEISMICITY_RATE,\n",
        "        name=name,\n",
        "        earthquake_criterion=earthquake_criterion,\n",
        "        catalog=catalog,\n",
        "    )\n",
        "\n",
        "    self.scaler = StandardScaler(feature_axes=(0, 1, 2, 3, 4))\n",
        "\n",
        "  @gin.configurable(\n",
        "      'SeismicityRateDataSet.prepare_features',\n",
        "      allowlist=['magnitudes', 'square_sizes', 'lookback_seconds'],\n",
        "  )\n",
        "  def prepare_features(\n",
        "      self,\n",
        "      space_times: LocationsPerTime,\n",
        "      magnitudes: Sequence[float] = gin.REQUIRED,\n",
        "      square_sizes: Sequence[float] = gin.REQUIRED,\n",
        "      lookback_seconds: Sequence[int] = gin.REQUIRED,\n",
        "      feature_functions: Sequence[\n",
        "          SeismicityRateFeature\n",
        "      ] = DEFAULT_SEISMICITY_RATE_FUNCTIONS,\n",
        "  ):\n",
        "    \"\"\"Generates a raw feature numpy array.\n",
        "\n",
        "    Args:\n",
        "      space_times: Times and locations at which to calculate the features. It is\n",
        "        expected to have the same number of locations per timestamp.\n",
        "      magnitudes: Magnitude thresholds to calculate seismicity.\n",
        "      square_sizes: Bin sizes (in meters, centered in the location center) for\n",
        "        calculation of seismicity rates.\n",
        "      lookback_seconds: Time intervals (in the past from the evaluation times)\n",
        "        for calculation of seismicity rates.\n",
        "      feature_functions: Functions for feature engineering.\n",
        "\n",
        "    Returns:\n",
        "      Numpy array of earthquake features. The first axis corresponds to\n",
        "      timestamps, the second to locations, the third to `magnitudes`, the\n",
        "      fourth to `square_sizes`, the fifth to `lookback_seconds` and the last to\n",
        "      `feature_functions`. For every timestamp T, location X, magnitude M,\n",
        "      distance S and lookback D we calculate N - the number of earthquakes with\n",
        "      magnitude at least M (in the filtered catalog) per second per km^2, in the\n",
        "      D seconds before T at distance at most S from location X. The features are\n",
        "      then calculated on the corresponding M, S, D, N.\n",
        "    \"\"\"\n",
        "    timestamps = np.array(sorted(space_times.keys()))\n",
        "    n_locations = len(next(iter(space_times.values())))\n",
        "    features = np.zeros((\n",
        "        len(space_times),\n",
        "        n_locations,\n",
        "        len(magnitudes),\n",
        "        len(square_sizes),\n",
        "        len(lookback_seconds),\n",
        "        len(feature_functions),\n",
        "    ))\n",
        "\n",
        "    square_sizes = np.array(square_sizes)\n",
        "    for magnitude_i, magnitude in enumerate(magnitudes):\n",
        "      sub_catalog = self._catalog[self._catalog.magnitude >= magnitude]\n",
        "      xs_from = np.subtract.outer(sub_catalog.x_utm.values, square_sizes / 2)\n",
        "      ys_from = np.subtract.outer(sub_catalog.y_utm.values, square_sizes / 2)\n",
        "      xs_to = np.add.outer(sub_catalog.x_utm.values, square_sizes / 2)\n",
        "      ys_to = np.add.outer(sub_catalog.y_utm.values, square_sizes / 2)\n",
        "      times_array = sub_catalog.time.values\n",
        "\n",
        "      for timestamp_i, timestamp in enumerate(timestamps):\n",
        "        loc_xs = np.array([location[0] for location in space_times[timestamp]])\n",
        "        loc_ys = np.array([location[1] for location in space_times[timestamp]])\n",
        "        last_index = np.searchsorted(times_array, timestamp, side='right')\n",
        "        for lookback_i, lookback in enumerate(lookback_seconds):\n",
        "          first_index = np.searchsorted(\n",
        "              times_array, timestamp - lookback, side='left'\n",
        "          )\n",
        "          time_slice = slice(first_index, last_index)\n",
        "\n",
        "          n_in_square = _num_in_square(\n",
        "              xs_from[time_slice],\n",
        "              ys_from[time_slice],\n",
        "              xs_to[time_slice],\n",
        "              ys_to[time_slice],\n",
        "              loc_xs,\n",
        "              loc_ys,\n",
        "          )\n",
        "          for feature_i, function in enumerate(feature_functions):\n",
        "            features[timestamp_i, :, magnitude_i, :, lookback_i, feature_i] = (\n",
        "                function(n_in_square, square_sizes, magnitude, lookback)\n",
        "            )\n",
        "    return features\n",
        "\n",
        "  @gin.configurable('SeismicityRateDataSet.generate_model')\n",
        "  def generate_model(\n",
        "      self,\n",
        "      input_size: int,\n",
        "      model_constructor: ModelConstructor = fully_connected_model,\n",
        "  ) -> tf.keras.Model:\n",
        "    \"\"\"Generates a model with the model constructor, and given input size.\n",
        "\n",
        "    Args:\n",
        "      input_size: The number of features in the input.\n",
        "      model_constructor: A method that creates a model.\n",
        "\n",
        "    Returns:\n",
        "      A model, provided by the model constructor.\n",
        "    \"\"\"\n",
        "    return model_constructor(self.name, input_size)\n",
        "\n",
        "\n",
        "@gin.configurable\n",
        "class LocationDataSet(BaseDataSet):\n",
        "  \"\"\"Data set with the location of the (bin of the) example.\n",
        "\n",
        "  The location is encoded as a 1-hot encoding of all the available bins.\n",
        "  \"\"\"\n",
        "\n",
        "  def __init__(\n",
        "      self,\n",
        "      projection: pyproj.Proj = JAPAN_PROJECTION,\n",
        "      name: str = 'current_location',\n",
        "  ):\n",
        "    \"\"\"Initializes the data set.\"\"\"\n",
        "    super().__init__(dataset_type=DataSetType.LOCATION, name=name)\n",
        "\n",
        "    self.projection = projection\n",
        "\n",
        "  @gin.configurable('LocationDataSet.prepare_features')\n",
        "  def prepare_features(\n",
        "      self,\n",
        "      space_times: LocationsPerTime,\n",
        "      bins_constructor: Callable[[], Rectangles] = Rectangles.init_grid,\n",
        "  ):\n",
        "    \"\"\"Prepares the features of the dataset.\n",
        "\n",
        "    Args:\n",
        "      space_times: Times and locations at which to calculate the features. It is\n",
        "        expected to have the same number of locations per timestamp.\n",
        "      bins_constructor: A division of the same space domain into bins. Provided\n",
        "        as a constructor, for use with Gin.\n",
        "\n",
        "    Returns:\n",
        "      A 3 dimensional array of features. For every time and location, there is a\n",
        "      1-hot encoding of which of the input bins contains the location.\n",
        "    \"\"\"\n",
        "    timestamps = np.array(sorted(space_times.keys()))\n",
        "    n_locations = len(next(iter(space_times.values())))\n",
        "    bins = bins_constructor()\n",
        "    features = np.zeros((timestamps.size, n_locations, bins.length))\n",
        "    for timestamp_i, timestamp in enumerate(timestamps):\n",
        "      for location_i, location in enumerate(space_times[timestamp]):\n",
        "        features[\n",
        "            timestamp_i, location_i, bins.index_of(location, self.projection)\n",
        "        ] = 1\n",
        "    return features\n",
        "\n",
        "  @gin.configurable('LocationDataSet.generate_model')\n",
        "  def generate_model(\n",
        "      self,\n",
        "      input_size: int,\n",
        "      model_constructor: ModelConstructor = fully_connected_model,\n",
        "  ) -> tf.keras.Model:\n",
        "    \"\"\"Generates a model with the model constructor, and given input size.\n",
        "\n",
        "    Args:\n",
        "      input_size: The number of features in the input.\n",
        "      model_constructor: A method that creates a model.\n",
        "\n",
        "    Returns:\n",
        "      A model, provided by the model constructor.\n",
        "    \"\"\"\n",
        "    return model_constructor(self.name, input_size)\n",
        "\n",
        "\n",
        "@gin.configurable\n",
        "class LocationCoordinatesDataSet(BaseDataSet):\n",
        "  \"\"\"Data set with two features: the location of the (bin of the) example.\"\"\"\n",
        "\n",
        "  def __init__(self, name: str = 'current_coordinates'):\n",
        "    \"\"\"Initializes the data set.\"\"\"\n",
        "    super().__init__(dataset_type=DataSetType.LOCATION_COORDINATES, name=name)\n",
        "\n",
        "  def prepare_features(self, space_times: LocationsPerTime):\n",
        "    \"\"\"Prepares the features of the dataset.\"\"\"\n",
        "    timestamps = np.array(sorted(space_times.keys()))\n",
        "    n_locations = len(next(iter(space_times.values())))\n",
        "    features = np.zeros((timestamps.size, n_locations, 2))\n",
        "    for timestamp_i, timestamp in enumerate(timestamps):\n",
        "      for location_i, location in enumerate(space_times[timestamp]):\n",
        "        features[timestamp_i, location_i, :] = location\n",
        "    return features\n",
        "\n",
        "  def generate_model(self) -> tf.keras.Model:\n",
        "    \"\"\"Prepares the keras model. In this case, it is the identity.\"\"\"\n",
        "    return identity_model(self.name, input_size=2)\n"
      ],
      "metadata": {
        "id": "C5JU2NF_2BND",
        "cellView": "form"
      },
      "execution_count": 8,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "#@title Data factory\n",
        "\n",
        "#@markdown Here we combine different data sets into a single object. The main\n",
        "#@markdown class is `DataFactory`. It handles the division of features into\n",
        "#@markdown train, validation and test tests, for each data set.\n",
        "\n",
        "FeaturesDict = dict[DataSetType, np.ndarray]\n",
        "\n",
        "T = TypeVar('T')\n",
        "\n",
        "\n",
        "class DataFactory:\n",
        "  \"\"\"Class that prepares feature data from individual datasets.\n",
        "\n",
        "  Usage:\n",
        "    factory = DataFactory([dataset1, dataset2, ...])\n",
        "    factory.add_dataset(dataset3)\n",
        "    data = factory.build(...)\n",
        "\n",
        "  Attributes:\n",
        "    datasets: A mapping between DataSetTypes and data sets. Each data set must\n",
        "      inherit from BaseDataSet.\n",
        "  \"\"\"\n",
        "\n",
        "  def __init__(self, datasets: Iterable[BaseDataSet]):\n",
        "    \"\"\"Initializes DataFactory from a list of datasets.\n",
        "\n",
        "    Args:\n",
        "      datasets: The datasets that will be used for feature extraction.\n",
        "    \"\"\"\n",
        "    ids = [dataset.type for dataset in datasets]\n",
        "    if len(ids) != len(set(ids)):\n",
        "      raise ValueError('Duplicate datasets.')\n",
        "    self.datasets = {dataset.type: dataset for dataset in datasets}\n",
        "\n",
        "  def add_dataset(self, dataset: BaseDataSet):\n",
        "    \"\"\"Adds a dataset to the DataFactory.\"\"\"\n",
        "    if dataset.type in self.datasets:\n",
        "      raise ValueError(f'A dataset of type {dataset.type} already exists.')\n",
        "    self.datasets[dataset.type] = dataset\n",
        "\n",
        "  def remove_dataset(self, dataset_type: DataSetType):\n",
        "    \"\"\"Removes a dataset from the DataFactory.\"\"\"\n",
        "    if dataset_type not in self.datasets:\n",
        "      raise KeyError(f'There is no dataset with type {dataset_type}.')\n",
        "    self.datasets.pop(dataset_type)\n",
        "\n",
        "  @gin.configurable(denylist=['self', 'space_times'])\n",
        "  def build_features(\n",
        "      self,\n",
        "      space_times: EvaluationSpaceTimes,\n",
        "      prepare_features_args: Mapping[DataSetType, Mapping[str, Any]] = {},\n",
        "      data_sets_to_normalize: Iterable[DataSetType] = tuple(),\n",
        "      training: bool = True,\n",
        "  ) -> FeatureData:\n",
        "    \"\"\"Prepares features for train and test splits.\n",
        "\n",
        "    The features always include the delta_time and earthquake_mask datasets.\n",
        "    The rest of the features are calculated up to the timestamp *before* the\n",
        "    evaluation time. In a sense, the input timestamps are the \"target\" (or\n",
        "    \"label\") times, and naturally we want to calculate the features before the\n",
        "    lead time.\n",
        "    Note that the time edges (e.g. train set start and end timestamps) are added\n",
        "    to the evaluation.\n",
        "\n",
        "    Args:\n",
        "      space_times: Times and locations at which to calculate the features. It is\n",
        "        expected to have the same number of locations per timestamp. Note that\n",
        "        some datasets may expect the timestamp to be after and some before the\n",
        "        lead time (=delta_time). This function expects the timestamps to be\n",
        "        after the lead time (i.e. it should include the exact space-time of the\n",
        "        target earthquake), and it will shift the timestamps to after the lead\n",
        "        time where appropriate.\n",
        "      prepare_features_args: Keyword arguments for the `prepare_features` method\n",
        "        of every dataset, keyed by their types. Usually unused, since we pass\n",
        "        arguments with Gin. But useful for tests nonetheless.\n",
        "      data_sets_to_normalize: Types of features to normalize.\n",
        "      training: Whether the function is being executed during training. If so,\n",
        "        scalers will be fitted to the training set. Otherwise, the stored\n",
        "        scalers will be used.\n",
        "\n",
        "    Returns:\n",
        "      A FeatureData object, containing training, validation, and testing data.\n",
        "    \"\"\"\n",
        "    times_to_locations_dict = {\n",
        "        'train': space_times.train_space_times,\n",
        "        'valid': space_times.validation_space_times,\n",
        "        'test': space_times.test_space_times,\n",
        "    }\n",
        "    left_edges = {\n",
        "        'train': space_times.train_start,\n",
        "        'valid': space_times.validation_start,\n",
        "        'test': space_times.test_start,\n",
        "    }\n",
        "\n",
        "    features = {part: {} for part in times_to_locations_dict}\n",
        "\n",
        "    # Prepare the two special datasets (delta_time and earthquake_mask).\n",
        "    for part, time_to_location in times_to_locations_dict.items():\n",
        "      # Earthquakes are marked after the lead time.\n",
        "      mask = EarthquakesMaskDataSet().prepare_features(\n",
        "          time_to_location\n",
        "      )\n",
        "      features[part][DataSetType.EARTHQUAKES_MASK] = mask\n",
        "\n",
        "      # Delta time is calculated on times with the right edges. Locations are\n",
        "      # ignored but their amounts are important.\n",
        "      left_edge = left_edges[part]\n",
        "      time_to_location[left_edge] = next(iter(time_to_location.values()))\n",
        "      lead_time = DeltaTimeDataSet().prepare_features(\n",
        "          time_to_location\n",
        "      )\n",
        "      features[part][DataSetType.DELTA_TIME] = lead_time\n",
        "      _ = time_to_location.pop(left_edge)\n",
        "\n",
        "      # Finally, the rest of the features are calculated before the lead time.\n",
        "      shifted_time_to_location = shift_locations_per_time(\n",
        "          time_to_location, left_edge\n",
        "      )\n",
        "      more_features = self._prepare_features(\n",
        "          shifted_time_to_location, prepare_features_args\n",
        "      )\n",
        "      for data_set_type, features_per_data_set in more_features.items():\n",
        "        features[part][data_set_type] = features_per_data_set\n",
        "\n",
        "    features = self._normalize(features, data_sets_to_normalize, training)\n",
        "\n",
        "    return FeatureData(\n",
        "        train_data=self._id_key_to_name_key(features['train']),\n",
        "        validation_data=self._id_key_to_name_key(features['valid']),\n",
        "        test_data=self._id_key_to_name_key(features['test']),\n",
        "    )\n",
        "\n",
        "  @gin.configurable(denylist=['self', 'space_times'])\n",
        "  def build_features_eval(\n",
        "      self,\n",
        "      space_times: Sequence[SampleSpaceTimes],\n",
        "      data_sets_to_normalize: Iterable[DataSetType],\n",
        "      do_not_flatten: Sequence[DataSetType],\n",
        "      calculate_earthquakes_mask: bool = False,\n",
        "  ) -> dict[str, np.ndarray]:\n",
        "    \"\"\"A version of the building features method, useful during evaluation.\n",
        "\n",
        "    Args:\n",
        "      space_times: Times and locations at which to calculate the features. It is\n",
        "        expected to have the same number of locations per timestamp, and sorted\n",
        "        by the history time.\n",
        "      data_sets_to_normalize: Types of features to normalize.\n",
        "      do_not_flatten: Types of feature types that should not be completely\n",
        "        flattened.\n",
        "      calculate_earthquakes_mask: Whether to calculate the earthquakes mask. It\n",
        "        is slow to compute, and normally is not used during evaluation.\n",
        "\n",
        "    Returns:\n",
        "      A dictionary between data set names and the corresponding features.\n",
        "    \"\"\"\n",
        "    # Technically, it's possible to extend this implementation to allow\n",
        "    # repeating history and lead times. However, it isn't necessary right now,\n",
        "    # and we can keep the implementation simpler.\n",
        "    assert np.all(np.diff([x.history_time for x in space_times]) > 0)\n",
        "    assert np.all(np.diff([x.eval_time for x in space_times]) > 0)\n",
        "\n",
        "    features = {}\n",
        "\n",
        "    history_to_locations = {x.history_time: x.locations for x in space_times}\n",
        "    eval_to_locations = {x.eval_time: x.locations for x in space_times}\n",
        "    lead_times = np.array([x.lead_time for x in space_times])\n",
        "    n_locations = len(space_times[0].locations)\n",
        "\n",
        "    if calculate_earthquakes_mask:\n",
        "      features[DataSetType.EARTHQUAKES_MASK] = (\n",
        "          EarthquakesMaskDataSet().prepare_features(eval_to_locations)\n",
        "      )\n",
        "    else:\n",
        "      features[DataSetType.EARTHQUAKES_MASK] = np.zeros(\n",
        "          (len(lead_times), n_locations, 1)\n",
        "      )\n",
        "    features[DataSetType.DELTA_TIME] = np.repeat(\n",
        "        lead_times.reshape((-1, 1, 1)), n_locations, axis=1\n",
        "    )\n",
        "\n",
        "    for dataset_type, dataset in self.datasets.items():\n",
        "      features[dataset_type] = dataset.prepare_features(history_to_locations)\n",
        "\n",
        "    for dataset_type in data_sets_to_normalize:\n",
        "      scaler = self.datasets[dataset_type].scaler\n",
        "      features[dataset_type] = scaler.transform(features[dataset_type])\n",
        "\n",
        "    for dataset_type, data in features.items():\n",
        "      if dataset_type in do_not_flatten:\n",
        "        features[dataset_type] = reshape_features_to_3d(data)\n",
        "      else:\n",
        "        features[dataset_type] = reshape_features_to_2d(data)\n",
        "\n",
        "    return self._id_key_to_name_key(features)\n",
        "\n",
        "  def build_models(\n",
        "      self,\n",
        "      generate_model_args: Mapping[DataSetType, Mapping[str, Any]],\n",
        "  ) -> dict[str, tf.keras.Model]:\n",
        "    \"\"\"Prepares models for every data set.\n",
        "\n",
        "    Args:\n",
        "      generate_model_args: Keyword arguments for the `generate_model` method of\n",
        "        every dataset, keyed by their types.\n",
        "\n",
        "    Returns:\n",
        "      A mapping between names of data sets and their models.\n",
        "    \"\"\"\n",
        "    models = {}\n",
        "    for dataset_type, dataset in self.datasets.items():\n",
        "      models[dataset.name] = dataset.generate_model(\n",
        "          **generate_model_args.get(dataset_type, {})\n",
        "      )\n",
        "    return models\n",
        "\n",
        "  def _prepare_features(\n",
        "      self,\n",
        "      times_to_locations: LocationsPerTime,\n",
        "      prepare_features_args: Mapping[DataSetType, Mapping[str, Any]],\n",
        "  ) -> FeaturesDict:\n",
        "    \"\"\"Prepares features for all datasets on a set of evaluation times.\"\"\"\n",
        "    features = {}\n",
        "    for dataset_type, dataset in self.datasets.items():\n",
        "      features[dataset_type] = dataset.prepare_features(\n",
        "          times_to_locations, **prepare_features_args.get(dataset_type, {})\n",
        "      )\n",
        "    return features\n",
        "\n",
        "  def _normalize(\n",
        "      self,\n",
        "      features: dict[str, FeaturesDict],\n",
        "      data_sets_to_normalize: Iterable[DataSetType],\n",
        "      training: bool,\n",
        "  ) -> dict[str, FeaturesDict]:\n",
        "    \"\"\"Normalizes the features.\"\"\"\n",
        "    for dataset_type in data_sets_to_normalize:\n",
        "      scaler = self.datasets[dataset_type].scaler\n",
        "      splits = ['train', 'valid', 'test']\n",
        "      if training:\n",
        "        features['train'][dataset_type] = scaler.fit_transform(\n",
        "            features['train'][dataset_type]\n",
        "        )\n",
        "        splits = ['valid', 'test']\n",
        "      for split in splits:\n",
        "        features[split][dataset_type] = scaler.transform(\n",
        "            features[split][dataset_type]\n",
        "        )\n",
        "    return features\n",
        "\n",
        "  def _id_key_to_name_key(\n",
        "      self, dictionary: dict[DataSetType, T]\n",
        "  ) -> dict[str, T]:\n",
        "    \"\"\"Converts a dictionary keyed by dataset ids to be keyed by their names.\"\"\"\n",
        "    result = {}\n",
        "    for dataset_type, value in dictionary.items():\n",
        "      if dataset_type in self.datasets:\n",
        "        result[self.datasets[dataset_type].name] = value\n",
        "      # These are specified concretely, because (1) they should not be in the\n",
        "      # list of datasets, and (2) they have a special wiring in the cumulative\n",
        "      # hazard model architecture.\n",
        "      elif dataset_type == DataSetType.EARTHQUAKES_MASK:\n",
        "        result['earthquakes_mask'] = value\n",
        "      elif dataset_type == DataSetType.DELTA_TIME:\n",
        "        result['delta_time'] = value\n",
        "    return result\n"
      ],
      "metadata": {
        "cellView": "form",
        "id": "DyjDh19ZPfEn"
      },
      "execution_count": 9,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "#@title The FERN model\n",
        "\n",
        "#@markdown The model is constructed as follows:\n",
        "#@markdown\n",
        "#@markdown There are different data sets (defined in the Data sets tab),\n",
        "#@markdown representing different physical measurements - time, catalog of\n",
        "#@markdown earthquakes, etc. Each such data set is represented as some array of\n",
        "#@markdown features, and has a model for encoding these features. FERN combines\n",
        "#@markdown these models into one, and attempts to learn all of their weights\n",
        "#@markdown in order to optimize the standard ETAS loss.\n",
        "\n",
        "_SECONDS_PER_DAY = 86400\n",
        "\n",
        "\n",
        "@dataclasses.dataclass(frozen=True)\n",
        "class CumulativeHazardOutput:\n",
        "  \"\"\"The different outputs of a cumulative hazard model.\n",
        "\n",
        "  The attributes are 3 tensors of equal length, each matching the model's\n",
        "  predicted values at time t, given data up to time t - dt.\n",
        "\n",
        "  Attributes:\n",
        "    hazard: The rate of occurrence of events at time t, as calculated by the\n",
        "      model.\n",
        "    cumulative_hazard: The integral of the hazard in the range [t - dt, t], as\n",
        "      calculated by the model.\n",
        "    earthquakes_mask: A binary mask that indicates whether an event occurred at\n",
        "      time t.\n",
        "  \"\"\"\n",
        "  hazard: tf.Tensor\n",
        "  cumulative_hazard: tf.Tensor\n",
        "  earthquakes_mask: tf.Tensor\n",
        "\n",
        "\n",
        "def abs_glorot_uniform(shape, dtype: Optional[str] = None):\n",
        "  \"\"\"Glorot uniform weight initializer that only returns positive values.\"\"\"\n",
        "  return tf.keras.backend.abs(\n",
        "      tf.keras.initializers.glorot_uniform(seed=None)(shape, dtype=dtype)\n",
        "  )\n",
        "\n",
        "\n",
        "def neg_glorot_uniform(shape, dtype: Optional[str] = None):\n",
        "  \"\"\"Glorot uniform weight initializer that only returns negative values.\"\"\"\n",
        "  return -abs_glorot_uniform(shape, dtype)\n",
        "\n",
        "\n",
        "class NonNegativeFloat64(tf.keras.constraints.Constraint):\n",
        "  \"\"\"Constrains the weights to be non-negative.\"\"\"\n",
        "\n",
        "  def __call__(self, weights: tf.Tensor):\n",
        "    return weights * tf.cast(tf.greater_equal(weights, 0), 'float64')\n",
        "\n",
        "\n",
        "class NonPositiveFloat64(tf.keras.constraints.Constraint):\n",
        "  \"\"\"Constrains the weights to be non-positive.\"\"\"\n",
        "\n",
        "  def __call__(self, weights: tf.Tensor):\n",
        "    return weights * tf.cast(tf.less_equal(weights, 0), 'float64')\n",
        "\n",
        "\n",
        "def _non_negative_weights_layer(\n",
        "    units: int,\n",
        "    activation: Optional[str] = 'tanh',\n",
        "    kernel_regularization: Optional[tf.keras.regularizers.Regularizer] = None,\n",
        ") -> tf.keras.layers.Layer:\n",
        "  \"\"\"Returns a dense layer with only non-negative weights.\"\"\"\n",
        "  return tf.keras.layers.Dense(\n",
        "      units,\n",
        "      activation=activation,\n",
        "      dtype='float64',\n",
        "      kernel_initializer=abs_glorot_uniform,\n",
        "      kernel_constraint=NonNegativeFloat64(),\n",
        "      kernel_regularizer=kernel_regularization,\n",
        "  )\n",
        "\n",
        "\n",
        "def _non_positive_weights_layer(\n",
        "    units: int,\n",
        "    activation: Optional[str] = 'tanh',\n",
        "    kernel_regularization: Optional[tf.keras.regularizers.Regularizer] = None,\n",
        ") -> tf.keras.layers.Layer:\n",
        "  \"\"\"Returns a dense layer with only non-positive weights.\"\"\"\n",
        "  return tf.keras.layers.Dense(\n",
        "      units,\n",
        "      activation=activation,\n",
        "      dtype='float64',\n",
        "      kernel_initializer=neg_glorot_uniform,\n",
        "      kernel_constraint=NonPositiveFloat64(),\n",
        "      kernel_regularizer=kernel_regularization,\n",
        "  )\n",
        "\n",
        "\n",
        "def _all_positive_layers(\n",
        "    layer_sizes: Sequence[int],\n",
        "    delta_time: tf.keras.layers.Layer,\n",
        "    combined_embedding: tf.keras.layers.Layer,\n",
        "    kernel_regularization: Optional[tf.keras.regularizers.Regularizer],\n",
        ") -> tf.keras.layers.Layer:\n",
        "  \"\"\"Adds only positive layers to two inputs layers.\"\"\"\n",
        "  # This combines delta_time and combined_embedding in one layer, where the\n",
        "  # weights that are applied on delta_time are positive (for monotonicity).\n",
        "  # Therefore, the activation (tanh) is performed manually below.\n",
        "  delta_time = _non_negative_weights_layer(\n",
        "      layer_sizes[0], None, kernel_regularization\n",
        "  )(delta_time)\n",
        "  cumulative_hazard = tf.keras.layers.Lambda(\n",
        "      lambda inputs: tf.keras.backend.tanh(inputs[0] + inputs[1]),\n",
        "      dtype='float64',\n",
        "  )([delta_time, combined_embedding])\n",
        "\n",
        "  for layer_size in layer_sizes[1:-1]:\n",
        "    cumulative_hazard = _non_negative_weights_layer(\n",
        "        layer_size, 'tanh', kernel_regularization\n",
        "    )(cumulative_hazard)\n",
        "  return _non_negative_weights_layer(\n",
        "      layer_sizes[-1], 'softplus', kernel_regularization\n",
        "  )(cumulative_hazard)\n",
        "\n",
        "\n",
        "def _half_positive_layers(\n",
        "    layer_size: int,\n",
        "    delta_time: tf.keras.layers.Layer,\n",
        "    combined_embedding: tf.keras.layers.Layer,\n",
        "    kernel_regularization: Optional[tf.keras.regularizers.Regularizer],\n",
        ") -> tf.keras.layers.Layer:\n",
        "  \"\"\"Adds a half-positive half-negative hidden layer.\"\"\"\n",
        "  # This combines delta_time and combined_embedding in one layer, where the\n",
        "  # weights that are applied on delta_time are constructed so that the output is\n",
        "  # monotonic in delta_time, and also can be concave (as a function of\n",
        "  # delta_time).\n",
        "  half_size = layer_size // 2\n",
        "  second_half_size = layer_size - half_size\n",
        "\n",
        "  delta_time_positive = _non_negative_weights_layer(\n",
        "      half_size, None, kernel_regularization\n",
        "  )(delta_time)\n",
        "  delta_time_negative = _non_positive_weights_layer(\n",
        "      second_half_size, None, kernel_regularization\n",
        "  )(delta_time)\n",
        "\n",
        "  # Split the combined embedding into two \"layers\", to combine separately with\n",
        "  # the two parts of the delta_time encoding.\n",
        "  combined_embedding_first = tf.keras.layers.Lambda(\n",
        "      lambda x: tf.slice(x, (0, 0), (-1, half_size)), dtype='float64'\n",
        "  )(combined_embedding)\n",
        "  combined_embedding_second = tf.keras.layers.Lambda(\n",
        "      lambda x: tf.slice(x, (0, half_size), (-1, second_half_size)),\n",
        "      dtype='float64',\n",
        "  )(combined_embedding)\n",
        "\n",
        "  cumulative_hazard_first = tf.keras.layers.Lambda(\n",
        "      lambda inputs: tf.keras.backend.tanh(inputs[0] + inputs[1]),\n",
        "      dtype='float64',\n",
        "  )([delta_time_positive, combined_embedding_first])\n",
        "  cumulative_hazard_second = tf.keras.layers.Lambda(\n",
        "      lambda inputs: tf.keras.backend.tanh(inputs[0] + inputs[1]),\n",
        "      dtype='float64',\n",
        "  )([delta_time_negative, combined_embedding_second])\n",
        "\n",
        "  output_positive = _non_negative_weights_layer(1, None, kernel_regularization)(\n",
        "      cumulative_hazard_first\n",
        "  )\n",
        "  output_negative = _non_positive_weights_layer(1, None, kernel_regularization)(\n",
        "      cumulative_hazard_second\n",
        "  )\n",
        "\n",
        "  return tf.keras.layers.Lambda(\n",
        "      lambda inputs: tf.keras.backend.softplus(inputs[0] + inputs[1]),\n",
        "      dtype='float64',\n",
        "  )([output_positive, output_negative])\n",
        "\n",
        "\n",
        "\n",
        "def cumulative_hazard_inputs_order(input_names: Sequence[str]) -> Sequence[str]:\n",
        "  \"\"\"Returns a canonical order for inputs to the cumulative hazard model.\"\"\"\n",
        "  return sorted(input_names)\n",
        "\n",
        "\n",
        "@gin.configurable(\n",
        "    denylist=[\n",
        "        'data_sets_models',\n",
        "        'log_transform_delta_time',\n",
        "        'delta_time_scaler',\n",
        "    ]\n",
        ")\n",
        "def cumulative_hazard_model(\n",
        "    data_sets_models: Mapping[str, tf.keras.Model],\n",
        "    log_transform_delta_time: bool,\n",
        "    delta_time_scaler: StandardScaler,\n",
        "    layer_sizes: Sequence[int],\n",
        "    kernel_regularization: Optional[tf.keras.regularizers.Regularizer] = None,\n",
        ") -> tf.keras.Model:\n",
        "  \"\"\"Constructs a cumulative hazard FERN model.\n",
        "\n",
        "  The output of this model is the cumulative hazard, and a binary mask which\n",
        "  indicates whether the trained example represents an earthquake. It has the\n",
        "  property that the partial derivative of the cumulative hazard with respect to\n",
        "  the delta_time input is positive (this is the hazard).\n",
        "\n",
        "  Args:\n",
        "    data_sets_models: Models of the underlying data sets, keyed by human\n",
        "      readable names.\n",
        "    log_transform_delta_time: Whether to apply log on the delta_time input.\n",
        "    delta_time_scaler: The scaler to apply to the delta_time input. If\n",
        "      `log_transform_delta_time` is True, this scaler should have been fit to\n",
        "      the log of delta_time.\n",
        "    layer_sizes: A list of sizes of the hidden and output layers.\n",
        "    kernel_regularization: Regularizer function.\n",
        "\n",
        "  Returns:\n",
        "    A cumulative hazard FERN model, and the order of the features that it\n",
        "    expects to get.\n",
        "  \"\"\"\n",
        "  delta_time_input = tf.keras.layers.Input(\n",
        "      shape=(1,), name='delta_time', dtype='float64'\n",
        "  )\n",
        "  delta_time = delta_time_input\n",
        "  mean, std = delta_time_scaler.mean, delta_time_scaler.std\n",
        "  if log_transform_delta_time:\n",
        "    delta_time = tf.keras.layers.Lambda(\n",
        "        lambda dt: (tf.keras.backend.log(dt) - mean) / std\n",
        "    )(delta_time)\n",
        "  else:\n",
        "    delta_time = tf.keras.layers.Lambda(lambda dt: (dt - mean) / std)(\n",
        "        delta_time\n",
        "    )\n",
        "\n",
        "  combined_embedding = tf.keras.layers.concatenate(\n",
        "      [model.output for model in data_sets_models.values()],\n",
        "      name='concatenated_embeddings',\n",
        "      dtype='float64',\n",
        "  )\n",
        "  combined_embedding = tf.keras.layers.Dense(\n",
        "      layer_sizes[0],\n",
        "      activation=None,\n",
        "      dtype='float64',\n",
        "      kernel_regularizer=kernel_regularization,\n",
        "  )(combined_embedding)\n",
        "\n",
        "  assert len(layer_sizes) >= 2\n",
        "  assert layer_sizes[-1] == 1\n",
        "  if len(layer_sizes) > 2:\n",
        "    cumulative_hazard = _all_positive_layers(\n",
        "        layer_sizes, delta_time, combined_embedding, kernel_regularization\n",
        "    )\n",
        "  else:\n",
        "    cumulative_hazard = _half_positive_layers(\n",
        "        layer_sizes[0], delta_time, combined_embedding, kernel_regularization\n",
        "    )\n",
        "\n",
        "  earthquakes_mask = tf.keras.layers.Input(\n",
        "      shape=(1,), name='earthquakes_mask', dtype='float64'\n",
        "  )\n",
        "\n",
        "  inputs = [model.input for _, model in data_sets_models.items()] + [\n",
        "      earthquakes_mask,\n",
        "      delta_time_input,\n",
        "  ]\n",
        "  inputs_order = cumulative_hazard_inputs_order(\n",
        "      [input.name for input in inputs]\n",
        "  )\n",
        "  inputs.sort(key=lambda input: inputs_order.index(input.name))\n",
        "\n",
        "  return tf.keras.Model(\n",
        "      inputs=inputs, outputs=[cumulative_hazard, earthquakes_mask]\n",
        "  )\n"
      ],
      "metadata": {
        "cellView": "form",
        "id": "8dFF_jX8RAAK"
      },
      "execution_count": 10,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "#@title Evaluation functions\n",
        "\n",
        "def hazard_from_cumulative_hazard(\n",
        "    cumulative_hazard: tf.Tensor,\n",
        "    gradient_tape: tf.GradientTape,\n",
        "    delta_time_tensor: tf.Tensor,\n",
        "    space_bin_area: float,\n",
        ") -> tf.Tensor:\n",
        "  \"\"\"Calculates the (properly scaled) hazard from a cumulative hazard model.\n",
        "\n",
        "  Args:\n",
        "    cumulative_hazard: The output of the model.\n",
        "    gradient_tape: A tape that recorded the forward pass of the model.\n",
        "    delta_time_tensor: A tensor containing the delta_time feature, expected to\n",
        "      be in seconds.\n",
        "    space_bin_area: The size of the space bin, expected to be in deg**2.\n",
        "\n",
        "  Returns:\n",
        "    The hazard, in [1/(day * deg**2)] units.\n",
        "  \"\"\"\n",
        "  hazard = gradient_tape.gradient(cumulative_hazard, delta_time_tensor)\n",
        "  # The gradient is taken with respect to delta_time in seconds, so we need to\n",
        "  # rescale.\n",
        "  hazard *= _SECONDS_PER_DAY\n",
        "  # The output is the cumulative hazard per bin, so we need to rescale again.\n",
        "  hazard /= space_bin_area\n",
        "  return hazard\n",
        "\n",
        "\n",
        "def get_model_output(\n",
        "    model: tf.keras.Model,\n",
        "    inputs_order: Sequence[str],\n",
        "    batch_features: Mapping[str, np.ndarray],\n",
        "    space_bin_area: float,\n",
        ") -> CumulativeHazardOutput:\n",
        "  \"\"\"Calculates the outputs of a cumulative hazard model.\n",
        "\n",
        "  Args:\n",
        "    model: A cumulative hazard model (assumed to match the architecture above).\n",
        "    inputs_order: The order of inputs expected by the model.\n",
        "    batch_features: The features tensors, possibly batched.\n",
        "    space_bin_area: The size of the space bin, expected to be in deg**2.\n",
        "\n",
        "  Returns:\n",
        "    The hazard values, the cumulative hazard values, and the earthquakes mask.\n",
        "    The last two are direct outputs form the model, and the first one is\n",
        "    calculated by backpropagation.\n",
        "  \"\"\"\n",
        "  delta_time_index = inputs_order.index('delta_time')\n",
        "  with tf.GradientTape() as tape:\n",
        "    tensors = [\n",
        "        tf.convert_to_tensor(batch_features[name], dtype=tf.float64)\n",
        "        for name in inputs_order\n",
        "    ]\n",
        "    tape.watch(tensors[delta_time_index])\n",
        "    cumulative_hazard_output, earthquakes_mask = model(tensors, training=False)\n",
        "\n",
        "  hazard = hazard_from_cumulative_hazard(\n",
        "      cumulative_hazard_output, tape, tensors[delta_time_index], space_bin_area\n",
        "  )\n",
        "  return CumulativeHazardOutput(\n",
        "      hazard, cumulative_hazard_output, earthquakes_mask\n",
        "  )\n",
        "\n"
      ],
      "metadata": {
        "id": "6RUomPtTgkTh",
        "cellView": "form"
      },
      "execution_count": 11,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "#@title The main training loop\n",
        "\n",
        "# A history type, for tracking measurements during learning.\n",
        "History = Mapping[str, Sequence[float]]\n",
        "\n",
        "\n",
        "_BATCH_SIZE_FOR_LOSS = 100\n",
        "\n",
        "\n",
        "@tf.function\n",
        "def cumulative_hazard_loss(\n",
        "    hazard: tf.Tensor, cumulative_hazard: tf.Tensor, earthquakes_mask: tf.Tensor\n",
        ") -> float:\n",
        "  \"\"\"The ETAS log likelihood score, calculated given the cumulative hazard.\n",
        "\n",
        "  Args:\n",
        "    hazard: The rate of occurrence of events at time t, as calculated by the\n",
        "      model.\n",
        "    cumulative_hazard: The integral of the hazard in the range [t - dt, t], as\n",
        "      calculated by the model.\n",
        "    earthquakes_mask: A binary mask that indicates whether an event occurred at\n",
        "      time t.\n",
        "\n",
        "  Returns:\n",
        "    The loss, which is the negative of the log likelihood score.\n",
        "  \"\"\"\n",
        "  return tf.keras.backend.sum(\n",
        "      cumulative_hazard - tf.math.log(1e-20 + hazard) * earthquakes_mask\n",
        "  )\n",
        "\n",
        "\n",
        "@gin.configurable\n",
        "def build_factory(\n",
        "    include_earthquakes_data: bool = True,\n",
        "    include_seismicity_data: bool = True,\n",
        ") -> DataFactory:\n",
        "  \"\"\"Builds a data factory with datasets determined by input flags.\n",
        "\n",
        "  Args:\n",
        "    include_earthquakes_data: Whether to use the RecentEarthquakesDataSet.\n",
        "    include_seismicity_data: Whether to use the SeismicityRateDataSet.\n",
        "\n",
        "  Returns:\n",
        "    A data factory.\n",
        "  \"\"\"\n",
        "  datasets = [LocationDataSet()]\n",
        "  if include_earthquakes_data:\n",
        "    datasets.append(RecentEarthquakesDataSet())\n",
        "  if include_seismicity_data:\n",
        "    datasets.append(SeismicityRateDataSet())\n",
        "  return DataFactory(datasets)\n",
        "\n",
        "\n",
        "def _dataset(\n",
        "    features: Mapping[str, np.ndarray], inputs_order: Sequence[str]\n",
        ") -> tf.data.Dataset:\n",
        "  \"\"\"Creates a tf.Dataset from a dictionary of features.\"\"\"\n",
        "\n",
        "  def _generator():\n",
        "    n_examples = next(iter(features.values())).shape[0]\n",
        "    for i in range(n_examples):\n",
        "      yield tuple([features[name][i, :] for name in inputs_order])\n",
        "\n",
        "  return tf.data.Dataset.from_generator(\n",
        "      _generator,\n",
        "      output_signature=tuple(\n",
        "          [\n",
        "              tf.TensorSpec(shape=features[name].shape[1:], dtype=tf.float64)\n",
        "              for name in inputs_order\n",
        "          ]\n",
        "      ),\n",
        "  )\n",
        "\n",
        "\n",
        "class _TrainWrapper:\n",
        "  \"\"\"Wraps some training methods, in order to speed them up with tf.function.\"\"\"\n",
        "\n",
        "  def __init__(\n",
        "      self,\n",
        "      model: tf.keras.Model,\n",
        "      learning_rate: float,\n",
        "      learning_rate_decay: float,\n",
        "      inputs_order: Sequence[str],\n",
        "      space_bin_area: float,\n",
        "  ):\n",
        "    \"\"\"Initializes the trainer.\n",
        "\n",
        "    Args:\n",
        "      model: The cumulative hazard model to train.\n",
        "      learning_rate: The learning rate of the optimizer.\n",
        "      learning_rate_decay: The multiplicative decay of the learning rate.\n",
        "      inputs_order: The order of inputs expected by the model.\n",
        "      space_bin_area: The size of the space bin, expected to be in deg**2.\n",
        "    \"\"\"\n",
        "    self._model = model\n",
        "    self._learning_rate = learning_rate\n",
        "    self._learning_rate_decay = learning_rate_decay\n",
        "    self._inputs_order = inputs_order\n",
        "    self._delta_time_index = inputs_order.index('delta_time')\n",
        "    self._space_bin_area = space_bin_area\n",
        "\n",
        "    self._model.compile(optimizer=tf.keras.optimizers.Adam(self._learning_rate))\n",
        "\n",
        "  @tf.function\n",
        "  def _train_step(self, batch: tf.Tensor):\n",
        "    \"\"\"Trains one step, and applies the gradients.\"\"\"\n",
        "    with tf.GradientTape(persistent=True) as tape:\n",
        "      tensors = [\n",
        "          tf.convert_to_tensor(feature, dtype=tf.float64) for feature in batch\n",
        "      ]\n",
        "      for tensor in tensors:\n",
        "        tape.watch(tensor)\n",
        "      cumulative_hazard, earthquakes_mask = self._model(tensors, training=True)\n",
        "      hazard = hazard_from_cumulative_hazard(\n",
        "          cumulative_hazard,\n",
        "          tape,\n",
        "          tensors[self._delta_time_index],\n",
        "          self._space_bin_area,\n",
        "      )\n",
        "      loss = cumulative_hazard_loss(\n",
        "          hazard=hazard,\n",
        "          cumulative_hazard=cumulative_hazard,\n",
        "          earthquakes_mask=earthquakes_mask,\n",
        "      )\n",
        "      # Add regularization.\n",
        "      loss += tf.keras.backend.sum(self._model.losses)\n",
        "\n",
        "    gradients = tape.gradient(loss, self._model.trainable_weights)\n",
        "    self._model.optimizer.apply_gradients(\n",
        "        zip(gradients, self._model.trainable_weights)\n",
        "    )\n",
        "\n",
        "  @tf.function\n",
        "  def _total_dataset_loss(self, dataset: tf.data.Dataset) -> float:\n",
        "    \"\"\"Calculates the total loss on the dataset.\"\"\"\n",
        "    total = np.float64(0)\n",
        "    for batch in dataset:\n",
        "      total += self._batch_loss(batch)\n",
        "    return total\n",
        "\n",
        "  @tf.function\n",
        "  def _batch_loss(self, batch: tf.Tensor) -> float:\n",
        "    \"\"\"Calculates the total loss on one batch (fast, not for training).\"\"\"\n",
        "    with tf.GradientTape() as tape:\n",
        "      tensors = [\n",
        "          tf.convert_to_tensor(feature, dtype=tf.float64) for feature in batch\n",
        "      ]\n",
        "      tape.watch(tensors[self._delta_time_index])\n",
        "      cumulative_hazard, earthquakes_mask = self._model(tensors, training=False)\n",
        "    hazard = hazard_from_cumulative_hazard(\n",
        "        cumulative_hazard,\n",
        "        tape,\n",
        "        tensors[self._delta_time_index],\n",
        "        self._space_bin_area,\n",
        "    )\n",
        "    return cumulative_hazard_loss(\n",
        "        hazard=hazard,\n",
        "        cumulative_hazard=cumulative_hazard,\n",
        "        earthquakes_mask=earthquakes_mask,\n",
        "    )\n",
        "\n",
        "  def fit_model(\n",
        "      self, feature_data: FeatureData, batch_size: int, epochs: int, log: bool,\n",
        "  ) -> tuple[History, tf.keras.Model]:\n",
        "    \"\"\"Fits the model to the data.\n",
        "\n",
        "    Args:\n",
        "      feature_data: Features for training and validation, ordered as perscribed\n",
        "        by the cumulative hazard model.\n",
        "      batch_size: The size of the batch per training step.\n",
        "      epochs: The number of epochs for training.\n",
        "      log: Whether to display a progress bar when training.\n",
        "\n",
        "    Returns:\n",
        "      The history of the loss during training, and the trained model.\n",
        "    \"\"\"\n",
        "    train_dataset = (\n",
        "        _dataset(feature_data.train_data, self._inputs_order)\n",
        "        .shuffle(buffer_size=10000)\n",
        "        .batch(batch_size)\n",
        "        .cache()\n",
        "    )\n",
        "    validation_dataset = (\n",
        "        _dataset(feature_data.validation_data, self._inputs_order)\n",
        "        .batch(batch_size)\n",
        "        .cache()\n",
        "    )\n",
        "    test_dataset = (\n",
        "        _dataset(feature_data.test_data, self._inputs_order)\n",
        "        .batch(batch_size)\n",
        "        .cache()\n",
        "    )\n",
        "\n",
        "    history = {'train_loss': [], 'validation_loss': [], 'test_loss': []}\n",
        "\n",
        "    for _ in tqdm.tqdm(range(epochs), disable=not log):\n",
        "      tf.keras.backend.set_value(\n",
        "          self._model.optimizer.learning_rate, self._learning_rate\n",
        "      )\n",
        "      self._learning_rate *= self._learning_rate_decay\n",
        "      for batch in train_dataset:\n",
        "        self._train_step(batch)\n",
        "\n",
        "      history['train_loss'].append(self._total_dataset_loss(train_dataset))\n",
        "      history['validation_loss'].append(\n",
        "          self._total_dataset_loss(validation_dataset)\n",
        "      )\n",
        "      history['test_loss'].append(self._total_dataset_loss(test_dataset))\n",
        "\n",
        "    return history, self._model\n",
        "\n",
        "\n",
        "@gin.configurable\n",
        "def train_and_evaluate_cumulative_hazard(\n",
        "    log_transform_delta_time: bool = True,\n",
        "    space_bin_area: float = gin.REQUIRED,\n",
        "    learning_rate: float = gin.REQUIRED,\n",
        "    learning_rate_decay: float = gin.REQUIRED,\n",
        "    batch_size: int = gin.REQUIRED,\n",
        "    epochs: int = gin.REQUIRED,\n",
        "    verbose: bool = False,\n",
        ") -> tuple[History, tf.keras.Model]:\n",
        "  \"\"\"Trains a cumulative hazard FERN model.\n",
        "\n",
        "  Arguments to the underlying classes and functions are passed with Gin,\n",
        "  therefore most of them are not specified in this function.\n",
        "\n",
        "  Args:\n",
        "    log_transform_delta_time: Whether to apply log on the delta_time input.\n",
        "    space_bin_area: The size of the space bin, expected to be in deg**2.\n",
        "    learning_rate: The learning rate of the optimizer.\n",
        "    learning_rate_decay: The multiplicative decay of the learning rate.\n",
        "    batch_size: The size of the batch per training step.\n",
        "    epochs: The number of epochs for training.\n",
        "    verbose: Whether to display a progress bar when training.\n",
        "\n",
        "  Returns:\n",
        "    The history object, tracking metrics over epochs.\n",
        "  \"\"\"\n",
        "  print('Creating features.')\n",
        "  space_times = (\n",
        "      EvaluationSpaceTimes.init_with_earthquake_times_and_locations()\n",
        "  )\n",
        "  factory = build_factory()\n",
        "  features = factory.build_features(space_times=space_times).to_flat_partial()\n",
        "\n",
        "  print('Creating a model.')\n",
        "  dataset_models = factory.build_models(generate_model_args={})\n",
        "  delta_time_scaler = StandardScaler(feature_axes=(0, 1))\n",
        "  if log_transform_delta_time:\n",
        "    delta_time_scaler.fit(np.log(features.train_data['delta_time']))\n",
        "  else:\n",
        "    delta_time_scaler.fit(features.train_data['delta_time'])\n",
        "  model = cumulative_hazard_model(\n",
        "      dataset_models, log_transform_delta_time, delta_time_scaler\n",
        "  )\n",
        "\n",
        "  print('Training the model.')\n",
        "  inputs_order = cumulative_hazard_inputs_order(\n",
        "      features.train_data.keys()\n",
        "  )\n",
        "  history, model = _TrainWrapper(\n",
        "      model, learning_rate, learning_rate_decay, inputs_order, space_bin_area\n",
        "  ).fit_model(features, batch_size, epochs, log=verbose)\n",
        "\n",
        "  return history, model, factory\n",
        "\n"
      ],
      "metadata": {
        "cellView": "form",
        "id": "cT710qcoSNBJ"
      },
      "execution_count": 12,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "# Training on a fake catalog"
      ],
      "metadata": {
        "id": "Z4zcSDO3CTJA"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# We'll create a year of fake data\n",
        "\n",
        "train_start_time = 0\n",
        "test_end_time = 86400 * 365"
      ],
      "metadata": {
        "id": "sAzOZusXaMDS"
      },
      "execution_count": 13,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "#@title Setting up the hyperparameters\n",
        "\n",
        "# One advantage of Gin is the ability to view the entire configuration of the\n",
        "# model in one location. We bind and explain some of the parameters below.\n",
        "# Note that these values are for the toy catalog. In the actual model, for\n",
        "# instance, we used a history of 80 and not 10 earthquakes, and the lookback\n",
        "# times for the Seismicity Rate data set were on the order of months and years.\n",
        "\n",
        "side_deg = 1\n",
        "\n",
        "validation_start_time = train_start_time + (test_end_time - train_start_time) * 0.6\n",
        "test_start_time = train_start_time + (test_end_time - train_start_time) * 0.8\n",
        "\n",
        "lng_range = (137, 142)\n",
        "lat_range = (35, 39)\n",
        "target_depth = 100\n",
        "target_magnitude = 2\n",
        "# It is possible to bind a lower value for the feature magnitude (or any other\n",
        "# parameter) with gin scoping.\n",
        "\n",
        "with gin.unlock_config():\n",
        "  # Take only earthquakes in our target rectangle, above the feature magnitude.\n",
        "  gin.bind_parameter('earthquake_criterion.longitude_range', lng_range)\n",
        "  gin.bind_parameter('earthquake_criterion.latitude_range', lat_range)\n",
        "  gin.bind_parameter('earthquake_criterion.max_depth', target_depth)\n",
        "  gin.bind_parameter('earthquake_criterion.min_magnitude', target_magnitude)\n",
        "  gin.bind_parameter('earthquake_criterion.start_timestamp', train_start_time)\n",
        "\n",
        "  # Train on a grid of locations in the target rectangle. Higher `grid_side_deg`\n",
        "  # will lead to better approximations of the spatial integral in the loss\n",
        "  # calculation, but increases the number of training examples - and therefore\n",
        "  # the training time.\n",
        "  gin.bind_parameter('init_with_earthquake_times_and_locations.train_start', train_start_time)\n",
        "  gin.bind_parameter('init_with_earthquake_times_and_locations.validation_start', validation_start_time)\n",
        "  gin.bind_parameter('init_with_earthquake_times_and_locations.test_start', test_start_time)\n",
        "  gin.bind_parameter('init_with_earthquake_times_and_locations.test_end', test_end_time)\n",
        "  gin.bind_parameter('init_with_earthquake_times_and_locations.longitude_range', lng_range)\n",
        "  gin.bind_parameter('init_with_earthquake_times_and_locations.latitude_range', lat_range)\n",
        "  gin.bind_parameter('init_with_earthquake_times_and_locations.grid_side_deg', side_deg)\n",
        "\n",
        "  # Settings for data sets.\n",
        "  # From our experiments, it helps to normalize the Recent Earthquakes data set.\n",
        "  # The Seismicity Rate data set is already normalized in a sense (since it's a\n",
        "  # rate for a given time range).\n",
        "  gin.bind_parameter('build_features.data_sets_to_normalize', [DataSetType.RECENT_EARTHQUAKES])\n",
        "  gin.bind_parameter('to_flat_partial.do_not_flatten', ['seismicity', 'earthquakes'])\n",
        "\n",
        "  gin.bind_parameter('init_rectangles_grid.longitude_range', lng_range)\n",
        "  gin.bind_parameter('init_rectangles_grid.latitude_range', lat_range)\n",
        "  gin.bind_parameter('init_rectangles_grid.side_deg', side_deg)  # Note - doesn't actually have to be the same grid size\n",
        "  gin.bind_parameter('LocationDataSet.prepare_features.bins_constructor', init_rectangles_grid)\n",
        "\n",
        "  max_earthquakes = 10  # Used also to build the model, below\n",
        "  gin.bind_parameter('RecentEarthquakesDataSet.prepare_features.max_earthquakes', max_earthquakes)\n",
        "  gin.bind_parameter('RecentEarthquakesDataSet.prepare_features.n_seconds', 86400 * 30 * 2)\n",
        "\n",
        "  magnitudes = (2, 3, 4) # Used also to build the model, below\n",
        "  square_sizes = (1e3, 4e3, 16e3, 64e3, 256e3)  # In meters, because of the UTM projection\n",
        "  lookback_seconds = (3600, 86400, 86400 * 7)\n",
        "  gin.bind_parameter('SeismicityRateDataSet.prepare_features.magnitudes', magnitudes)\n",
        "  gin.bind_parameter('SeismicityRateDataSet.prepare_features.square_sizes', square_sizes)\n",
        "  gin.bind_parameter('SeismicityRateDataSet.prepare_features.lookback_seconds', lookback_seconds)\n",
        "\n",
        "  # Settings for data set models construction.\n",
        "  gin.bind_parameter('LocationDataSet.generate_model.input_size',\n",
        "      int((lng_range[1] - lng_range[0]) * (lat_range[1] - lat_range[0]) / (side_deg ** 2)))\n",
        "  gin.bind_parameter('fully_connected_model.layer_sizes', [16])\n",
        "  gin.bind_parameter('fully_connected_model.activation', 'tanh')\n",
        "  gin.bind_parameter('fully_connected_model.kernel_regularization', tf.keras.regularizers.l2(1e-4))\n",
        "  gin.bind_parameter('LocationDataSet.generate_model.model_constructor', fully_connected_model)\n",
        "\n",
        "  gin.bind_parameter('RecentEarthquakesDataSet.generate_model.input_size',\n",
        "      (max_earthquakes, len(DEFAULT_CATALOG_FUNCTIONS)))\n",
        "  gin.bind_parameter('order_invariant_cnn_model.cnn_filters', [16, 8])\n",
        "  gin.bind_parameter('order_invariant_cnn_model.activation', 'tanh')\n",
        "  gin.bind_parameter('order_invariant_cnn_model.kernel_regularization', tf.keras.regularizers.l2(1e-4))\n",
        "  gin.bind_parameter('RecentEarthquakesDataSet.generate_model.model_constructor', order_invariant_cnn_model)\n",
        "\n",
        "  gin.bind_parameter('SeismicityRateDataSet.generate_model.input_size',\n",
        "      (len(magnitudes) * len(square_sizes) * len(lookback_seconds), len(DEFAULT_SEISMICITY_RATE_FUNCTIONS)))\n",
        "  gin.bind_parameter('cnn_1d_model.cnn_filters', [16, 8])\n",
        "  gin.bind_parameter('cnn_1d_model.dense_units', [16])\n",
        "  gin.bind_parameter('cnn_1d_model.activation', 'tanh')\n",
        "  gin.bind_parameter('cnn_1d_model.kernel_regularization', tf.keras.regularizers.l2(1e-4))\n",
        "  gin.bind_parameter('SeismicityRateDataSet.generate_model.model_constructor', cnn_1d_model)\n",
        "\n",
        "  # Settings for the construction of the head model.\n",
        "  gin.bind_parameter('cumulative_hazard_model.layer_sizes', [64, 1])\n",
        "  gin.bind_parameter('cumulative_hazard_model.kernel_regularization', tf.keras.regularizers.l2(1e-8))\n",
        "\n",
        "  # Parameters for the main training loop. These are fairly standard\n",
        "  # hyperparameters for a training loop.\n",
        "  gin.bind_parameter('train_and_evaluate_cumulative_hazard.space_bin_area', side_deg ** 2)\n",
        "  gin.bind_parameter('train_and_evaluate_cumulative_hazard.learning_rate', 3e-4)\n",
        "  gin.bind_parameter('train_and_evaluate_cumulative_hazard.learning_rate_decay', 0.995)\n",
        "  gin.bind_parameter('train_and_evaluate_cumulative_hazard.batch_size', 32)\n",
        "  gin.bind_parameter('train_and_evaluate_cumulative_hazard.epochs', 20)\n",
        "\n"
      ],
      "metadata": {
        "id": "HAZPpG5O--2I"
      },
      "execution_count": 14,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "#@title Set up a random catalog in Japan, projecting the coordinates to UTM\n",
        "\n",
        "#@markdown Doesn't have all the statistical properties of a real catalog, this\n",
        "#@markdown is just to show how to train the model.\n",
        "\n",
        "def _random_magnitudes(\n",
        "    rs: np.random.RandomState,\n",
        "    size: int,\n",
        "    beta: float = 1.6,\n",
        "    min_mag: float = 2,\n",
        "    max_mag: float = 9\n",
        ") -> list[float]:\n",
        "  \"\"\"Random magnitudes, drawn according to the Gutenberg-Richter law.\"\"\"\n",
        "  res = np.ones(size) * max_mag\n",
        "  while np.any(res >= max_mag):\n",
        "    random_for_inverson = rs.uniform(size=size)\n",
        "    res = (-1 * np.log(1 - random_for_inverson) / beta) + min_mag\n",
        "  return list(res)\n",
        "\n",
        "\n",
        "def _random_etas_times_magnitudes(\n",
        "    background_rate_per_sec: float = 1e-5,\n",
        "    seed: int = 42,\n",
        "    from_time: int = 0,\n",
        "    to_time: int = 86400 * 365,\n",
        "    min_mag: float = 2,\n",
        "    etas_a: float = 0.3,\n",
        "    etas_alpha: float = 1.2,\n",
        "    etas_c: float = 1500,  # In seconds\n",
        "    etas_p: float = 1.2,\n",
        ") -> list[tuple[float, float]]:\n",
        "  \"\"\"Samples random times and magnitudes for earthquakes with the ETAS formula.\"\"\"\n",
        "  rs = np.random.RandomState(seed)\n",
        "\n",
        "  # Start with background events:\n",
        "  generations = []\n",
        "  n_background = int(rs.poisson((to_time - from_time) * background_rate_per_sec))\n",
        "  new_times = rs.uniform(from_time, to_time, size=n_background)\n",
        "  new_magnitudes = _random_magnitudes(rs, n_background, min_mag=min_mag)\n",
        "  generations.append(list(zip(new_times, new_magnitudes)))\n",
        "\n",
        "  # Sample earthquakes in generations:\n",
        "  while len(generations[-1]) > 0:\n",
        "    new_times, new_magnitudes = [], []\n",
        "    for t, m in generations[-1]:\n",
        "      expected_n_aftershocks = etas_a * np.exp(etas_alpha * (m - min_mag))\n",
        "      n_aftershocks = rs.poisson(expected_n_aftershocks)\n",
        "      # Sample aftershock times\n",
        "      inversion = rs.uniform(0, 1, n_aftershocks)\n",
        "      aftershock_times = t + etas_c * (np.power(inversion, 1 / (1 - etas_p)) - 1)\n",
        "      aftershock_times = [at for at in aftershock_times if at < to_time]\n",
        "      new_times += aftershock_times\n",
        "      new_magnitudes += _random_magnitudes(rs, len(aftershock_times))\n",
        "    generations.append(list(zip(new_times, new_magnitudes)))\n",
        "\n",
        "  return sorted(itertools.chain(*generations[:-1]))\n",
        "\n",
        "\n",
        "def sample_catalog(\n",
        "    from_time: int = 0,\n",
        "    to_time: int = 86400 * 365,\n",
        "    center: tuple[float, float] = (37, 140),\n",
        "    location_var: tuple[float, float] = (0.6, 2),\n",
        "    location_cov: float = -1,\n",
        "    min_magnitude: float = 2,\n",
        "    seed: int = 42,\n",
        ") -> pd.DataFrame:\n",
        "  \"\"\"Creates a sample catalog, with random earthquakes in Japan.\"\"\"\n",
        "  random_state = np.random.RandomState(seed=seed)\n",
        "\n",
        "  times, magnitudes = zip(*_random_etas_times_magnitudes(\n",
        "      from_time=from_time, to_time=to_time, min_mag=min_magnitude))\n",
        "  cov_mat = ((location_var[0], location_cov), (location_cov, location_var[1]))\n",
        "  lat, lng = random_state.multivariate_normal(\n",
        "      center, cov_mat, size=len(times)).T\n",
        "  depths = random_state.uniform(low=0, high=100, size=len(times))\n",
        "\n",
        "  catalog = pd.DataFrame({\n",
        "      'time': times, 'longitude': lng, 'latitude': lat, 'depth': depths, 'magnitude': magnitudes,\n",
        "  })\n",
        "  catalog['x_utm'], catalog['y_utm'] = JAPAN_PROJECTION(\n",
        "      catalog['longitude'].values, catalog['latitude'].values\n",
        "  )\n",
        "  catalog = catalog.sort_values('time')\n",
        "  return catalog.copy()\n",
        "\n",
        "random_catalog = sample_catalog(\n",
        "    from_time=train_start_time, to_time=test_end_time)\n",
        "\n",
        "fig, axs = plt.subplots(ncols=2, nrows=2, figsize=(15, 10))\n",
        "_ = axs[0][0].scatter(random_catalog.time, random_catalog.magnitude, s=1)\n",
        "_ = axs[0][0].set_title('Events sequence')\n",
        "_ = axs[0][0].set_xlabel('Time (seconds)')\n",
        "_ = axs[0][0].set_ylabel('Mangitude')\n",
        "_ = axs[0][1].hist(random_catalog.magnitude, bins=20, log=True)\n",
        "_ = axs[0][1].set_title('Magnitude distribution')\n",
        "_ = axs[1][0].hist2d(random_catalog.longitude, random_catalog.latitude,\n",
        "                  bins=(np.arange(136, 144, 0.5), np.arange(34, 40, 0.5)))\n",
        "_ = axs[1][0].set_title('Location distribution - lat/lng')\n",
        "_ = axs[1][1].hist2d(random_catalog.x_utm, random_catalog.y_utm, bins=30)\n",
        "_ = axs[1][1].set_title('Location distribution - UTM')"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 853
        },
        "cellView": "form",
        "id": "6tb7hceCCXNE",
        "outputId": "edd5cf9f-b03c-40d1-f6ed-1a4d7e18db44"
      },
      "execution_count": 15,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<Figure size 1500x1000 with 4 Axes>"
            ],
            "image/png": "iVBORw0KGgoAAAANSUhEUgAABMQAAANECAYAAABfJ/OsAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzde3wU1d0/8M8mWTYxkgsXxSAGGhW5yKVRQFGMiFBMQbTeUFq01VYaiz4+PC38LEaKFNr6WEtN8dJW2qZSa1VQUwS8INUaQeQixgcUY7SJCApJMC5hs5nfH8sZzs7OzM7sbfbyeb9eiNnszpw5M7Ps+e73fI9LURQFREREREREREREGSLL6QYQERERERERERElEgNiRERERERERESUURgQIyIiIiIiIiKijMKAGBERERERERERZRQGxIiIiIiIiIiIKKMwIEZERERERERERBmFATEiIiIiIiIiIsooDIgREREREREREVFGYUCMiIiIiIiIiIgyCgNiREREREREGWrgwIG48cYbE7KvlStXwuVy4aOPPkr4fioqKlBRURHX/Qoulwv33HOP+vM999wDl8uFzz//PCH7T+Q5JUplDIgRpQnxD7/Rn/r6eqebiH//+9+455570Nra6nRTiIiIiGJK/iz22muvhfxeURQMGDAALpcL3/zmNx1ooTUNDQ2455574h60SgXJ/Nk1mdtGlCpynG4AEcXWz372MwwaNCjk8dNPP92B1gT797//jUWLFuHGG29EUVGR080hIiIiirnc3Fw8/vjjuOCCC4Ief/XVV/Gf//wHHo/HoZbp2717N7KyjudJNDQ0YNGiRaioqMDAgQOda1iMrV+/3vZrIv3s6vV6kZMT36G2Wdu055SI9DEgRpRmpk6dinPOOcfpZhARERFlpMsuuwxPPvkkli9fHhQUefzxx1FeXp6waXNWJVuALl569OgR1+13d3fj6NGjyM3NRW5ublz3FU6mnFOiaDFsTJRBfD4fevXqhZtuuinkd+3t7cjNzcW8efPUxzo7O1FdXY3TTz8dHo8HAwYMwI9//GN0dnYGvdblcuG2227D6tWrMXz4cHg8HgwbNgwvvPCC+px77rkH//M//wMAGDRokDqlQKTjb9iwARdccAGKiopw4oknYvDgwfh//+//hT0mK6+zehydnZ34r//6L/Tt2xc9e/bE9OnT8Z//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BAC88sorQfudNGmSmp0EACNGjEBBQQE+/PDDsG0WWVJr1qwxTKWP9HVWj+Of//wnAGDu3LlBr7/jjjsst0fr6aefRnd3N6655pqgfffr1w9nnHFGSB+eeOKJmDVrlvpzjx49MGbMmKA+fOqpp9CnTx/86Ec/CtmfmK755JNPorCwEJdeemnQfsvLy3HiiSeG7JeIiIhi65prroHX68Xzzz+Pw4cP4/nnnzecLgkgKKPp0KFDaGtrw4UXXoi3335bfVxMx/vhD38Y9Fq9zwTCrbfeGvTzhRdeiC+++ALt7e22jseuf/7znxg3bhzGjBmjPta3b1/ccMMNQc/bsGEDWltbMXPmzKDPLNnZ2Rg7dmzYzyxW96OnqKgI//nPf7BlyxabR3fcRRddhKFDh1p+flVVVdDP4tyJz6Hx8s9//hNjxowJWujhxBNPxPe//3189NFHaGhoCHr+TTfdFDST5MILLwQAS5/riVIJp0wSpZkxY8aYFtXPycnBt771LTz++OPo7OyEx+PB008/DZ/PFxQQe//99/Hee+8Zpl7v378/6OfTTjst5DnFxcWWalZde+21+P3vf4+bb74Z8+fPxyWXXIIrr7wSV111lekKOVZeZ/U4mpqakJWVFRTUA4DBgweHbb+R999/H4qi4IwzztD9vXba4qmnnhpSg6y4uBg7d+5Uf967dy8GDx5sunLR+++/j7a2Npx00km6v9eeOyIiIoqtvn37YtKkSXj88cfx1Vdfwe/346qrrjJ8/vPPP497770X27dvD6pxKn8uEJ9VtKuJm60krv18VlxcDCAQdCsoKLB1THY0NTVh7NixIY9rP1e9//77AKB+UakVro1W96PnJz/5CV588UWMGTMGp59+OiZPnozrr78e48ePD/taQW9ldzPaz4RlZWXIyspSa3/Fi1E/iamwTU1NGD58uPq42XVDlE4YECPKQNdddx0efvhhrF27FjNmzMDf//53nHXWWRg5cqT6nO7ubpx99tm4//77dbcxYMCAoJ+zs7N1n6coStj25OXlYdOmTXjllVdQV1eHF154AU888QQmTpyI9evXG27byuvsHocVeoXzgUB9L1l3dzdcLhfWrl2rewwnnnhi0M/R9KF2vyeddBL++te/6v7eKDhIREREsXP99dfjlltuwb59+zB16tSguqGyf/3rX5g+fTomTJiA3/3udzjllFPgdrvx2GOPqQXeIxWrzxbhaD8DWSUy/P/yl7+gX79+Ib83+wIwWkOGDMHu3bvx/PPP44UXXsBTTz2F3/3ud7j77ruxaNEiS9uwUqvMjPYzpdXPmPGWqOuGyGkMiBFloAkTJuCUU07BE088gQsuuAAvv/wy7rrrrqDnlJWVYceOHbjkkksM/3G2y2w7WVlZuOSSS3DJJZfg/vvvx89//nPcddddeOWVVzBp0qSIX2f1OEpLS9Hd3a1mYAm7d+8OeW5xcTFaW1tDHm9qagr6uaysDIqiYNCgQTjzzDMN921HWVkZ3nzzTfh8PsPC+GVlZXjxxRcxfvz4qD+oERERUWSuuOIK/OAHP0B9fX1QqQqtp556Crm5uVi3bh08Ho/6+GOPPRb0PPFZpbGxMSjTKNar/5l9XtL7DHT06FF8+umnIW0V2V8y7ecqkZl/0kknmX7eM2J1P0by8/Nx7bXX4tprr8XRo0dx5ZVXYsmSJViwYAFyc3Nj9hlYeP/994Oyyj744AN0d3erxfhFJpa2j7WfMQHz86RVWlqq2yf/93//p/6eKBOxhhhRBsrKysJVV12F5557Dn/5y1/Q1dUVNF0SCNS+aG5uxqOPPhryeq/Xi46ODtv7zc/PBxD6j/zBgwdDnjtq1CgACJo2oGXldVaPQ6wCpV356YEHHgh5XVlZGdra2oKmMn766ad45plngp535ZVXIjs7G4sWLQr5Rk1RFHzxxReGx2bkW9/6Fj7//HM8+OCDIb8T+7jmmmvg9/uxePHikOd0dXXpBvOIiIgotk488USsWLEC99xzD6ZNm2b4vOzsbLhcrqAsoI8++ihkRe8pU6YAAH73u98FPf7b3/42do2G8ec1IPAZaNOmTUGPPfLIIyEZTJdddhnq6+uxefNm9bEDBw6EZK9PmTIFBQUF+PnPfw6fzxeyvwMHDpi21ep+9Gg/h/Xo0QNDhw6FoihqW8z6IhI1NTVBP4tzJz6HFhQUoE+fPiF9rD3ndtt22WWXYfPmzXjjjTfUxzo6OvDII49g4MCBtuqgEaUTZogRpZm1a9eq3/bIzj//fHzta19Tf7722mvx29/+FtXV1Tj77LNDltP+9re/jb///e+49dZb8corr2D8+PHw+/34v//7P/z973/HunXrTGuV6SkvLwcA3HXXXbjuuuvgdrsxbdo0/OxnP8OmTZtQWVmJ0tJS7N+/H7/73e9w6qmnBhX/1LLyOqvHMWrUKMycORO/+93v0NbWhvPPPx8vvfSS7reu1113HX7yk5/giiuuwNy5c9Xlwc8888yg4rdlZWW49957sWDBAnz00UeYMWMGevbsicbGRjzzzDP4/ve/j3nz5tnqw+985zv485//jDvvvBObN2/GhRdeiI6ODrz44ov44Q9/iMsvvxwXXXQRfvCDH2Dp0qXYvn07Jk+eDLfbjffffx9PPvkkfvOb35jWMSEiIqLYmD17dtjnVFZW4v7778c3vvENXH/99di/fz9qampw+umnB335Vl5ejm9961t44IEH8MUXX2DcuHF49dVXsWfPHgD2MobMjBo1CtnZ2fjFL36BtrY2eDweTJw4ESeddBJuvvlm3HrrrfjWt76FSy+9FDt27MC6devQp0+foG38+Mc/xl/+8hd84xvfwO233478/Hw88sgjKC0tDTqmgoICrFixAt/+9rfx9a9/Hddddx369u2Ljz/+GHV1dRg/frzul4B296Nn8uTJ6NevH8aPH4+TTz4Z7733Hh588EFUVlaiZ8+eAIw/u4pglF2NjY2YPn06vvGNb+CNN95AbW0trr/++qCyJTfffDOWLVuGm2++Geeccw42bdqknmOZnbbNnz8fq1atwtSpUzF37lz06tULf/rTn9DY2IinnnrKtGYvUVpzanlLIootsdS30R/t8s3d3d3KgAEDFADKvffeq7vNo0ePKr/4xS+UYcOGKR6PRykuLlbKy8uVRYsWKW1tberzAChVVVUhr9cu+awoirJ48WKlf//+SlZWlrpU9EsvvaRcfvnlSklJidKjRw+lpKREmTlzprJnzx7TY7b6OqvH4fV6lblz5yq9e/dW8vPzlWnTpimffPKJ7hLj69evV4YPH6706NFDGTx4sFJbW6suqa311FNPKRdccIGSn5+v5OfnK2eddZZSVVWl7N69W33ORRddpLv09+zZs5XS0tKgx7766ivlrrvuUgYNGqS43W6lX79+ylVXXaXs3bs36HmPPPKIUl5eruTl5Sk9e/ZUzj77bOXHP/6x0tLSYtqvREREZJ/4LLZlyxbT55WWliqVlZVBj/3hD39QzjjjDMXj8ShnnXWW8thjj+l+rujo6FCqqqqUXr16KSeeeKIyY8YMZffu3QoAZdmyZerzxGsPHDig28bGxsag9mg/rz366KPK1772NSU7O1sBoLzyyiuKoiiK3+9XfvKTnyh9+vRRTjjhBGXKlCnKBx98oLuNnTt3KhdddJGSm5ur9O/fX1m8eLHyhz/8IWT/iqIor7zyijJlyhSlsLBQyc3NVcrKypQbb7xReeutt0z70s5+LrroIuWiiy5Sf3744YeVCRMmKL1791Y8Ho9SVlam/M///E/QZ0NF0f/sqijGn3/F7+TPjuJ8NDQ0KFdddZXSs2dPpbi4WLntttsUr9cb9NqvvvpK+d73vqcUFhYqPXv2VK655hpl//79up9Hjdqmdz727t2rXHXVVUpRUZGSm5urjBkzRnn++eeDnvPKK68oAJQnn3wy6PHGxkbd8QRRqnMpCivjERGZcblcqK6uxj333ON0U4iIiIiCbN++HaNHj0ZtbS1uuOEGp5tDRJQymBtJRERERESUArxeb8hjDzzwALKysjBhwgQHWkRElLpYQ4yIiIiIiCgF/PKXv8TWrVtx8cUXIycnB2vXrsXatWvx/e9/HwMGDHC6eUREKYUBMSIiIiIiohRw/vnnY8OGDVi8eDG+/PJLnHbaabjnnntw1113Od00IqKUwxpiRERERERERESUUVhDjIiIiIiIiIiIMgoDYkRERERERERElFFSuoZYd3c3Wlpa0LNnT7hcLqebQ0RERClCURQcPnwYJSUlyMri94PJiJ/ziIiIKBJWP+eldECspaWFq6kQERFRxD755BOceuqpTjeDdPBzHhEREUUj3Oe8lA6I9ezZE0DgIAsKChxuDREREaWK9vZ2DBgwQP0sQcmHn/OIiIgoElY/56V0QEykzxcUFPCDEhEREdnGqXjJi5/ziIiIKBrhPuexaAYREREREREREWUUBsSIiIiIiIiIiCijMCBGREREREREREQZhQExIiIiIiIiIiLKKAyIERERERERERFRRmFAjIiIiIiIiIiIMgoDYkRERERERERElFEYECMiIiIiIiIioozCgBgREREREREREWUUBsSIiIiIiIiIiCijMCBGREREREREREQZhQExIiIiIoq51tZWnHPOORg1ahSGDx+ORx991OkmEREREalynG4AxUZtfRNWbNyLORVlmDWu1OnmEBERUYbr2bMnNm3ahBNOOAEdHR0YPnw4rrzySvTu3dvpphERERExIJYuVmzci+ZWL1Zs3MuAGBERETkuOzsbJ5xwAgCgs7MTiqJAURSHWxVs4Py6uG7/o2WVcd0+ERERRY5TJtPEnIoy9C/Kw5yKMqebQkRERGlg06ZNmDZtGkpKSuByubB69eqQ59TU1GDgwIHIzc3F2LFjsXnz5qDft7a2YuTIkTj11FPxP//zP+jTp0+CWk9ERERkztGA2MCBA+FyuUL+VFVVOdmslDRrXClenz+R2WFEREQUEx0dHRg5ciRqamp0f//EE0/gzjvvRHV1Nd5++22MHDkSU6ZMwf79+9XnFBUVYceOHWhsbMTjjz+Ozz77LFHNJyIiIjLlaEBsy5Yt+PTTT9U/GzZsAABcffXVTjaLiIiIKONNnToV9957L6644grd399///245ZZbcNNNN2Ho0KF46KGHcMIJJ+CPf/xjyHNPPvlkjBw5Ev/6178M99fZ2Yn29vagP0RERETx4mhArG/fvujXr5/65/nnn0dZWRkuuugiJ5tFRERERCaOHj2KrVu3YtKkSepjWVlZmDRpEt544w0AwGeffYbDhw8DANra2rBp0yYMHjzYcJtLly5FYWGh+mfAgAHxPQgiIiLKaElTQ+zo0aOora3Fd7/7XbhcLqebQ0REREQGPv/8c/j9fpx88slBj5988snYt28fAKCpqQkXXnghRo4ciQsvvBA/+tGPcPbZZxtuc8GCBWhra1P/fPLJJ3E9BiIiIspsSbPK5OrVq9Ha2oobb7zR8DmdnZ3o7OxUf2YqPREREVFyGjNmDLZv3275+R6PBx6PJ34NIiIiIpIkTYbYH/7wB0ydOhUlJSWGz2EqPREREZHz+vTpg+zs7JAi+Z999hn69evnUKuIiIiIrEuKgFhTUxNefPFF3HzzzabPYyo9ERERkfN69OiB8vJyvPTSS+pj3d3deOmll3Deeec52DIiIiIia5JiyuRjjz2Gk046CZWVlabPYyo9ERERUWJ8+eWX+OCDD9SfGxsbsX37dvTq1QunnXYa7rzzTsyePRvnnHMOxowZgwceeAAdHR246aabotpvTU0Nampq4Pf7oz0EIiIiIkOOB8S6u7vx2GOPYfbs2cjJcbw5RERERATgrbfewsUXX6z+fOeddwIAZs+ejZUrV+Laa6/FgQMHcPfdd2Pfvn0YNWoUXnjhhZBC+3ZVVVWhqqoK7e3tKCwsjGpbREREREYcj0C9+OKL+Pjjj/Hd737X6aYQERER0TEVFRVQFMX0Obfddhtuu+22BLWIiIiIKHYcD4hNnjw57IctIiIiIiIiIiKiWEmKovpERERERERERESJwoAYERERERERERFlFAbEiIiIiChp1NTUYOjQoTj33HOdbgoRERGlMQbEiIiIiChpVFVVoaGhAVu2bHG6KURERJTGGBCjjFVb34Txy15GbX2T000hIiIiIiIiogRyfJVJIqes2LgXza1erNi4F7PGlTrdHCIiIkozA+fXxXX7Hy2rjOv2iYiI0hkzxChjzakoQ/+iPMypKHO6KURERERERESUQMwQo4w1a1wpM8OIiIiIiIiIMhAzxIiIiIgoaXCVSSIiIkoEBsSIiIiIKGlwlUkiIiJKBAbEiIiIiIiIiIgoozAgRkREREREREREGYUBMSIiIiIiIiIiyigMiBERERERERERUUZhQIyIiIiIiIiIiDIKA2JERERElDRqamowdOhQnHvuuU43hYiIiNIYA2JERERElDSqqqrQ0NCALVu2ON0UIiIiSmMMiBERERERERERUUZhQIyIiIiIiIiIiDIKA2JERBRTtfVNGL/sZdTWNzndFCIiIiIiIl0MiBERUUyt2LgXza1erNi41+mmEBERERER6WJAjIiIYmpORRn6F+VhTkWZ000hIiIiIiLSleN0A4iIKL3MGleKWeNKnW4GERERERGRIWaIEREREVHSqKmpwdChQ3Huuec63RQiIiJKYwyIEREREVHSqKqqQkNDA7Zs2eJ0U4iIiCiNMSBGREREREREREQZhQExIiIiIiIiIiLKKCyqT0RERESUggbOr4vr9j9aVhnX7RMRETmJGWJERERERERERJRRGBAjIiIiIiIiIqKMwoAYERERERERERFlFAbEiIiIiIiIiIgoozAgRkREREREREREGYUBMSIiIiJKGjU1NRg6dCjOPfdcp5tCREREaYwBMSIiIiJKGlVVVWhoaMCWLVucbgoRERGlMQbEiIiIiIiIiIgoozAgRkREREREREREGYUBMSIiIiIiIiIiyigMiBERERERERERUUZhQIyIiIiIiIiIiDIKA2JERERERERERJRRGBAjIiIiIiIiIqKMwoAYERERERERERFlFAbEKK5q65swftnLqK1vcropREREREREREQAGBCjOFuxcS+aW71YsXGv000hSisMNhMREREREUUux+kGUHqbU1GGFRv3Yk5FmdNNIUorcrB51rhSp5tDRERpaOD8urhu/6NllXHdPhERkRkGxCiuZo0r5WCdKA4YbCaidFVTU4Oamhr4/X6nm0JERERpjAExIqIUxGAzEaWrqqoqVFVVob29HYWFhU43h4iIiNIUa4gREREREREREVFGYUCMiIiIiIiIiIgyCgNiRERERERERESUURgQIyIiIiIiIiKijOJ4QKy5uRmzZs1C7969kZeXh7PPPhtvvfWW080iIiIiIiIiIqI05WhA7NChQxg/fjzcbjfWrl2LhoYG/O///i+Ki4udbFZGqq1vwvhlL6O2vsnpphARERERERERxVWOkzv/xS9+gQEDBuCxxx5THxs0aJCDLcpcKzbuRXOrFys27sWscaVON4eIiIiIiIiIKG4czRB79tlncc455+Dqq6/GSSedhNGjR+PRRx81fH5nZyfa29uD/lBszKkoQ/+iPMypKHO6KUREREREREREceVoQOzDDz/EihUrcMYZZ2DdunWYM2cO5s6diz/96U+6z1+6dCkKCwvVPwMGDEhwi9PXrHGleH3+RGaHEREREREREVHaczQg1t3dja9//ev4+c9/jtGjR+P73/8+brnlFjz00EO6z1+wYAHa2trUP5988kmCW0xERERERERERKnO0YDYKaecgqFDhwY9NmTIEHz88ce6z/d4PCgoKAj6Q0REREREREREZIejAbHx48dj9+7dQY/t2bMHpaWctkdERERERERERPHhaEDsv/7rv1BfX4+f//zn+OCDD/D444/jkUceQVVVlZPNIiIiIiIiIiKiNOZoQOzcc8/FM888g1WrVmH48OFYvHgxHnjgAdxwww1ONouIiIiIiIiIiNJYjtMN+OY3v4lvfvObTjeDiIiIiIiIiIgyhKMZYkRERERERERERInGgBgREREREREREWUUx6dMEhEREREJNTU1qKmpgd/vd7opFGcD59fFdfsfLauM6/aJiCi1MUOMiCgF1dY3Yfyyl1Fb3+R0U4iIYqqqqgoNDQ3YsmWL000hIiKiNMaAGBFRClqxcS+aW71YsXGv000hIiIiIiJKOQyIERGloDkVZehflIc5FWVON4WIiIiIiCjlsIYYEVEKmjWuFLPGlTrdDCIiIiIiopTEDDEiIiIiIiIiIsooDIgRERHFABc6ICIiIiJKHQyIUcbjIJaIYoELHRARERERpQ4GxCjjcRBLRLHAhQ6IiIiIiFIHi+pTxptTUYYVG/dyEEtEUeFCB0REREREqYMBMcp4sR7E1tY3qQE2Do6JiIiIiIiIkg+nTBLFGKdgEhERERERESU3BsSIYox1hIiIiIiIiIiSG6dMEsUY6wgRERERERERJTdmiBEZqK1vwvhlL6O2vsnpphARERERERFRDDEgRmSAtcCIiIiIiIiI0hOnTBIZmFNRpq4WSURERESpZeD8urhu/6NllXHdPhERxRcDYkQGWAuMiIiIiIiIKD1xyiRRGmL9MyIiIiIiIiJjDIgRpSHWPyMiIiIiIiIyxoAYURqaU1GG/kV5rH9GREREREREpIM1xIjSEOufERERERERERljhhgREREREREREWUUBsSIiIiIiIiIiCijMCBGRERkAVdvJSIiIiJKHwyIERERWcDVW4ns++STT1BRUYGhQ4dixIgRePLJJ51uEhEREREABsSIiIgs4eqtRPbl5OTggQceQENDA9avX4877rgDHR0dTjeLiIiIiKtMEhERWcHVW4nsO+WUU3DKKacAAPr164c+ffrg4MGDyM/Pd7hlRERElOmYIUaUAKw9RJmE1ztR+ti0aROmTZuGkpISuFwurF69OuQ5NTU1GDhwIHJzczF27Fhs3rxZd1tbt26F3+/HgAED4txqIiIiovAYECNKANYeokzC650ofXR0dGDkyJGoqanR/f0TTzyBO++8E9XV1Xj77bcxcuRITJkyBfv37w963sGDB/Gd73wHjzzySCKaTURERBQWp0xSRqqtb8KKjXsxp6IsIVOg5lSUqfsjSne83onSx9SpUzF16lTD399///245ZZbcNNNNwEAHnroIdTV1eGPf/wj5s+fDwDo7OzEjBkzMH/+fJx//vmG2+rs7ERnZ6f6c3t7e4yOgig+Bs6vi+v2P1pWGdftExFlOmaIUUZKdAbLrHGleH3+RNYfoozA650oMxw9ehRbt27FpEmT1MeysrIwadIkvPHGGwAARVFw4403YuLEifj2t79tur2lS5eisLBQ/cOplURERBRPDIgRgMyr+cPV4oiIiKLz+eefw+/34+STTw56/OSTT8a+ffsAAK+//jqeeOIJrF69GqNGjcKoUaPwzjvv6G5vwYIFaGtrU/988skncT8GIiIiylycMkkAgjOmMiGrg6vFERERxd8FF1yA7u5uS8/1eDzweDxxbhERERFRADPECEDmZUxlWkYcERFRrPXp0wfZ2dn47LPPgh7/7LPP0K9fP4daRURERGQNA2IEIPNq/nAVPCIiouj06NED5eXleOmll9THuru78dJLL+G8885zsGVERERE4XHKJGUkroJHREQU3pdffokPPvhA/bmxsRHbt29Hr169cNppp+HOO+/E7Nmzcc4552DMmDF44IEH0NHRoa46GYmamhrU1NTA7/fH4hCIiIiIdLkURVGcbkSk2tvbUVhYiLa2NhQUFDjdHCIiIkoR/AxhzcaNG3HxxReHPD579mysXLkSAPDggw/iV7/6Ffbt24dRo0Zh+fLlGDt2bNT7TsQ5Gji/Li7bJYqFj5ZVOt0EIqKUZPUzBDPEiIiIiEhXRUUFwn13etttt+G2225LUIuIiIiIYoM1xNIEi8QTEREREREREVnDgFiaYJF4IiIiIiIiIiJrGBBLE3MqytC/KI9F4omIiCil1dTUYOjQoTj33HOdbgoRERGlMdYQSxOzxpVi1rhSp5tBREREFJWqqipUVVWpBXGJiIiI4oEZYkRERERERERElFEYECMiIiIiIiIioozCgBgREREREREREWUUBsSIHFRb34Txy15GbX2T000hIiIiIiIiyhhRB8SOHDkSi3YQZaQVG/eiudWLFRv3Ot0UophjwJeIIsFVJomIiCgRIgqIdXd3Y/Hixejfvz9OPPFEfPjhhwCAhQsX4g9/+ENMG0iUzuZUlKF/UR7mVJQ53RSimGPAl4giUVVVhYaGBmzZssXpphAREVEaiyggdu+992LlypX45S9/iR49eqiPDx8+HL///e8tb+eee+6By+UK+nPWWWdF0iQCszFS0axxpXh9/kTMGlfqdFOIYo4BXyIiIiIiSlY5kbzoz3/+Mx555BFccskluPXWW9XHR44cif/7v/+zta1hw4bhxRdfPN6gnIiaRAjOxmCAhYicNmtcKd+LiIiIiIgoKUWUIdbc3IzTTz895PHu7m74fD5b28rJyUG/fv3UP3369ImkSRmvtr4JHZ1dKMpzo7y02HamGLPLYov9ScmE1yMREREREVGwiAJiQ4cOxb/+9a+Qx//xj39g9OjRtrb1/vvvo6SkBF/72tdwww034OOPPzZ8bmdnJ9rb24P+UMCKjXvR6vUh35ODrU2HbNftYa2f2GJ/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APWwWDiRNYm+V+K5v0yfDpzpx09ERERE6cWlKIridCMi1d7ejsLCQrS1taGgoMDp5qS08cteRnOrF/2L8vD6/Ikhv2ddHqLUxfuXKBQ/QyS/RJyjgfPr4rJdIgI+WlbpdBOIKENZ/QwRUQ0xSj+cAkiUvjjVjYiIiIiIKJitVSaF4uJiuFyukMddLhdyc3Nx+umn48Ybb8RNN90UdQMpMTgFkCg1RJLtxaluREREREREwSIKiN19991YsmQJpk6dijFjxgAANm/ejBdeeAFVVVVobGzEnDlz0NXVhVtuuSWmDSYiymR69fzCBckY8CYiIiIiIgoWUUDstddew7333otbb7016PGHH34Y69evx1NPPYURI0Zg+fLlDIglOdYWYh9QatHL9uKiF0SUTmpqalBTUwO/3+90U4iIiCiNRVRDbN26dZg0aVLI45dccgnWrVsHALjsssvw4YcfRtc6ijvWFmIfJEJtfRPGL3sZtfVNTjcl5enV8wtXA5BSD+8ZymRVVVVoaGjAli1bnG4KERERpbGIAmK9evXCc889F/L4c889h169egEAOjo60LNnz+haR3HHgbTzfZAJA18GHePLbNGLTLi+0lE63TO8BomIiIgoGUU0ZXLhwoWYM2cOXnnlFbWG2JYtW/DPf/4TDz30EABgw4YNuOiii2LXUooL1hZyrg/EVM2Ozi60en1pPd2NRd2dYzadktOFk1c63TOc0ktEREREySiiDLFbbrkFr776KvLz8/H000/j6aefxgknnIBXX30V3/ve9wAA//3f/40nnngipo0lSidikAgg7bP0zDKYKL7MMiDtZCExyyexUuGesXpNOJ2FS0RERESkJ6IMMQAYP348xo8fH8u2EGUUOQMkmQe9lNrMMiDtZCExy4e0rF4TzEQmIiIiomQUcUCsu7sbH3zwAfbv34/u7u6g302YMCHqhhElUiymjtndRiYMEjklL7nZuQbTaQofxQavCSIiMjNwfl1ct//Rssq4bp+I0l9EAbH6+npcf/31aGpqgqIoQb9zuVxcJptSTiyyX5hBE4p9kj4yIYBL9vCaICIiIqJUFlFA7NZbb8U555yDuro6nHLKKXC5XLFuFyVYpmfyxCLTgdkSodgnRGRVpv87RERE9jADjYiiFVFA7P3338c//vEPnH766bFuD0Uo2oFEpmfyaDMdIulP8TxR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A6vXmt3rUttOcX6Xzxxt+brW3qNi+rHe4iBmxxzNPUXxd/ToUWzduhULFixQH8vKysKkSZPwxhtvAADGjBmDXbt2obm5GYWFhVi7di0WLlxouE2nPucREVFySvWFT1K9/fGWDIsOJM0qk3PmzMHatWvx2muv4dRTT9V9TmdnJzo7O9Wf29vbMWDAAMdXiLKySl68yas9Th8ZHFwxWqlMGwywsiqm0Wp32mMX2+/s8getzqi3EqTe6mmx7Ef5WOVV4TY3HgzKktL2m97rra7MaNZPgL2V2yIhr1ioPSazcxAtK9daJPuK5NpI1Gti8dpI9yFWkCzKy8HhI10YVhJY1VR7bs1WsIzmOMyeK78nidVWI+2bWPVttNuxel+FW8k12nbE6hzFcj/x2E687ymuMmmPy+XCM888gxkzZgA4Xh/s3//+N8477zz1eT/+8Y/x6quv4s033wQAPPvss5g3bx66u7vx4x//GN///vcN9+HE5zwOVoiIiJwRz4CY1c95SREQu+2227BmzRps2rQJgwYNsvw6fpglIiKiSPAzhD2RBsSikYhzxIAYERGRM5IhIObolElFUfCjH/0IzzzzDDZu3GgrGEZEREREzujTpw+ys7Px2WfBNfU+++wz9OvXz6FWEREREVnnaFH9qqoq1NbW4vHHH0fPnj2xb98+7Nu3D16vN/yLiYiIiMgRPXr0QHl5OV566SX1se7ubrz00ktBGWNEREREycrRDLEVK1YAACoqKoIef+yxx3DjjTcmvkFEREREBAD48ssv8cEHH6g/NzY2Yvv27ejVqxdOO+003HnnnZg9ezbOOeccjBkzBg888AA6Ojpw0003RbXfmpoa1NTUwO/3h38yERERUYQcnzJJRERERMnnrbfewsUXX6z+fOeddwIAZs+ejZUrV+Laa6/FgQMHcPfdd2Pfvn0YNWoUXnjhBZx88slR7beqqgpVVVVq/Q8iIiKieHA0IEZEREREyamioiLsl5e33XYbbrvttgS1iIiIiCh2HK0hRkRERERERERElGgMiBERERERERERUUZhQIyIiIiIiIiIiDIKA2JERERElDRqamowdOhQnHvuuU43hYiIiNIYA2JERERElDSqqqrQ0NCALVu2ON0UIiIiSmMMiBERERERERERUUZhQIyIiIiIiIiIiDJKjtMNiIaiKACA9vZ2h1tCREREqUR8dhCfJSj5JOJzXnfnV3HbNhERERmL57/vVj/npXRA7PDhwwCAAQMGONwSIiIiSkWHDx9GYWGh080gHfycR0RElL4KH4j/PsJ9znMpKfzVaHd3N1paWtCzZ0+4XK6Ybbe9vR0DBgzAJ598goKCgphtN12xv+xjn9nD/rKPfWYP+8u+VO8zRVFw+PBhlJSUICuLFSSSUbw+5wmpfg2nKva7M9jvzmC/O4P97oxk6nern/NSOkMsKysLp556aty2X1BQ4PiJTCXsL/vYZ/awv+xjn9nD/rIvlfuMmWHJLd6f84RUvoZTGfvdGex3Z7DfncF+d0ay9LuVz3n8SpSIiIiIiIiIiDIKA2JERERERERERJRRGBDT4fF4UF1dDY/H43RTUgL7yz72mT3sL/vYZ/awv+xjn1Gq4zXsDPa7M9jvzmC/O4P97oxU7PeULqpPRERERERERERkFzPEiIiIiIiIiIgoozAgRkREREREREREGYUBMSIiIiIiIiIiyigMiBERERERERERUUbJ2IBYTU0NBg4ciNzcXIwdOxabN282ff6TTz6Js846C7m5uTj77LPxz3/+M0EtTQ52+mvlypVwuVxBf3JzcxPYWmdt2rQJ06ZNQ0lJCVwuF1avXh32NRs3bsTXv/51eDwenH766Vi5cmXc25lM7PbZxo0bQ64xl8uFffv2JabBDlu6dCnOPfdc9OzZEyeddBJmzJiB3bt3h31dJr+PRdJnmfxetmLFCowYMQIFBQUoKCjAeeedh7Vr15q+JpOvL0otkb6HUnQieV+h2Fu2bBlcLhfuuOMOp5uS1u65556QzxBnnXWW083KCM3NzZg1axZ69+6NvLw8nH322XjrrbecblZaGzhwoO7YrKqqyummhZWRAbEnnngCd955J6qrq/H2229j5MiRmDJlCvbv36/7/H//+9+YOXMmvve972Hbtm2YMWMGZsyYgV27diW45c6w218AUFBQgE8//VT909TUlMAWO6ujowMjR45ETU2Npec3NjaisrISF198MbZv34477rgDN998M9atWxfnliYPu30m7N69O+g6O+mkk+LUwuTy6quvoqqqCvX19diwYQN8Ph8mT56Mjo4Ow9dk+vtYJH0GZO572amnnoply5Zh69ateOuttzBx4kRcfvnlePfdd3Wfn+nXF6WWSN8PKDp231co9rZs2YKH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6c+fCK5evTrHD6379u3LsSB2/vx52e122Ww257L27durSpUqql69ujp27KiOHTuqR48eCg4O1t69e5WWlqb27du79HPx4kVn0SwpKUmtWrVyORrrktTUVP32229q2bKly/KWLVvqhx9+yHX85cqVc461bt262r17d7YTgkdHR7sUxJ577jk9/vjj+vjjj9WuXTv17NlTNWrUcHlMUFCQ8wg7AFKTJk2UlZWl5OTka54TbP/+/Vq9erW+/PLLAkoHAACAmwEFMQD5cmVByWazuSy7VMRyOByS/jyyo2vXrnrllVey9XWpoHSlkiVLKi0tTRcvXlRAQIAkKSwsTFu2bFFCQoKWLVumUaNGacyYMUpMTNTZs2clSV9//bUqVKjg0pfdbpf0Z5HJHa421rwYM2aMHn30UX399ddasmSJRo8erTlz5rgU0k6dOqVSpUq5JS9wszh79qz27t3rvL9//34lJSWpePHiql27tnr16qU+ffro9ddfV5MmTXTixAmtXLlSUVFRzqM2pT+PQC1Xrpw6derkjWEAAACgkOIcYgAKVNOmTbVz505VrVpVNWvWdLmFhITk+JjGjRtLknbt2uWy3M/PT+3atdOrr76qbdu26cCBA1q1apXq168vu92uQ4cOZdtGpUqVJP15ZNe3336rjIyMbNsLDw9X+fLl9d1337ks/+6771S/fv08j7VevXrasGGDy7L169dna1e7dm0NGTJEy5Yt01//+leXk4JfuHBB+/btcx7ZBljFpk2b1KRJE+dr/7nnnlOTJk00atQoSdKMGTPUp08fDR06VHXq1FH37t2VmJioypUrO/twOByaOXOm+vbtm+2nlQAAALA2jhADUKAGDhyoadOm6ZFHHtHzzz+v4sWLa+/evZozZ44++OCDHD+0lipVSk2bNtXatWudxbFFixbpl19+0Z133qlixYpp8eLFcjgcqlOnjsLCwjRs2DANGTJEDodDd9xxh1JSUvTdd98pPDxcMTExGjRokN566y09/PDDio2NVUREhNavX69bb71VderU0fDhwzV69GjVqFFDjRs31owZM5SUlKRZs2bleazPPPOMWrZsqYkTJ6pbt26Kj493+bnk+fPnNXz4cD3wwAOqVq2afv31VyUmJur+++93tlm/fr3sdrvzXGiAVbRu3VrGmFzX+/v7a+zYsRo7dmyubXx8fHT48GFPxAMAAMBNjiPEABSoS0deZWVl6Z577tEtt9yiZ599VpGRkfLxyf0t6fHHH3cpRkVGRmr+/Plq06aN6tWrp/fee0+ffPKJGjRoIEn6v//7P/3rX/9SXFyc6tWrp44dO+rrr79WtWrVJEklSpTQqlWrdPbsWd11111q1qyZpk2b5vwJ5DPPPKPnnntOQ4cO1S233KKlS5fqyy+/zPGk97m5/fbbNW3aNE2ePFmNGjXSsmXLnBcgkP4859rJkyfVp08f1a5dWw8++KA6derk8gH/k08+Ua9evRQcHJzn7QIAAAAArs5mrvb1KwAUEufPn1edOnX06aefWuZoqd9//1116tTRpk2bnIU8AAAAAED+cYQYgJtCUFCQPvroI/3+++/ejlJgDhw4oHfffZdiGAAAAAC4GUeIAQAAAAAAwFI4QgwAAAAAAACWQkEMAAAAAAAAlkJBDAAAAAAAAJZCQQwAAAAAAACWQkEMuEmNGTNGNpvN2zGcDhw4IJvNppkzZzqXFWTG1q1bq3Xr1s77CQkJstlsmjdvXoFsv2/fvqpatWqBbCs/bDabxowZ4/Ht5PR6AAAA7sF+oCv2AwHcCApigKSZM2fKZrNp06ZN3o7iIi0tTWPGjFFCQoK3oxSY3377TWPGjFFSUpK3o2RTmLN52q5duzRmzBgdOHAg1zZfffWVfHx8dOzYsYILBgBAPrEfWHgU5n2twpwtLy4VLSdOnJjj+okTJ8pms+nAgQPOfxPXul0qAl4qfvr4+Ojw4cPZ+k5NTVVQUJBsNpsGDRrkyWEC14WCGFCIpaWlaezYsTnuCL344os6f/58wYe6DjeS8bffftPYsWOve2dj2bJlWrZs2XU95npdLdu0adO0Z88ej27fm3bt2qWxY8detSD29ddfq1mzZipbtmzBBQMAoIhiPzDv2A90rzvvvFMff/yxy81ut6tVq1YuyyZNmuTyOLvdrk8++SRbf/Pnzy+g5MD18fN2AAA3xs/PT35+hfufcEFkTEtLU3BwsAICAjy6nWvx9/f36vYLg8WLF+uxxx7zdgwAAIo89gP/xH6gZ1SvXl3Vq1d3WfbUU0+pevXq+tvf/pbr4zp37qxPPvlEzz//vMvy2bNnq0uXLvr88889khe4URwhBlyHrVu3qlOnTgoPD1doaKjatm2r9evXZ2t3+vRpDRkyRFWrVpXdblfFihXVp08f/f7775KkixcvatSoUWrWrJkiIiIUEhKiVq1aafXq1c4+Dhw4oFKlSkmSxo4d6zw0+dL5n3I6L0NmZqb+7//+TzVq1JDdblfVqlX1z3/+U+np6S7tqlatqnvvvVdr167VrbfeqsDAQFWvXl0fffRRnubh9OnT6tu3ryIiIhQZGamYmBidPn06W7ucMi5fvlx33HGHIiMjFRoaqjp16uif//ynpD/P9/CXv/xFktSvXz/nmC+dj6J169Zq2LChNm/erDvvvFPBwcHOx1557ohLsrKy9M9//lNly5ZVSEiI7rvvvmyHcletWlV9+/bN9tjL+7xWtpzOHXHu3DkNHTpUlSpVkt1uV506dTRx4kQZY1zaXTp8fOHChWrYsKHsdrsaNGigpUuXZsvkbgcPHtTTTz+tOnXqKCgoSCVKlFDPnj1djgSbOXOmevbsKUm6++67nWO//Bvr7du36/Dhw+rSpUuu2+rbt69CQ0N15MgRde/eXaGhoSpVqpSGDRumrKwsl7YnT55U7969FR4e7nyN/fDDD5yXDADgNewH/m987AcWjf1Ad3v00UeVlJSkH3/80bns2LFjWrVqlR599FEvJgNyVri/VgAKkZ07d6pVq1YKDw/X888/L39/f02dOlWtW7fWmjVrdNttt0mSzp49q1atWmn37t167LHH1LRpU/3+++/68ssv9euvv6pkyZJKTU3VBx98oEceeURPPPGEzpw5o+nTp6tDhw7auHGjGjdurFKlSmnKlCkaMGCAevToob/+9a+SpKioqFwzPv744/rwww/1wAMPaOjQodqwYYPi4uK0e/duLViwwKXt3r179cADD6h///6KiYnRf/7zH/Xt21fNmjVTgwYNct2GMUbdunXT2rVr9dRTT6levXpasGCBYmJi8jSH9957r6KiovTSSy/Jbrdr7969+u677yRJ9erV00svvaRRo0bpySefVKtWrSRJLVq0cPZx8uRJderUSQ8//LD+9re/qUyZMlfd5rhx42Sz2TRixAglJydr0qRJateunZKSkhQUFHTNzJfkJdvljDG67777tHr1avXv31+NGzdWfHy8hg8friNHjujNN990ab927VrNnz9fTz/9tMLCwvTvf/9b999/vw4dOqQSJUrkOef1SkxM1Pfff6+HH35YFStW1IEDBzRlyhS1bt1au3btUnBwsO68804988wz+ve//61//vOfqlevnnNOLlm8eLFKly6t5s2bX3V7WVlZ6tChg2677TZNnDhRK1as0Ouvv64aNWpowIABkiSHw6GuXbtq48aNGjBggOrWrasvvvgiT68xAAA8gf3AP7EfWLT2A93tzjvvVMWKFTV79my99NJLkqRPP/1UoaGhV/3SFPAaA8DMmDHDSDKJiYm5tunevbsJCAgw+/btcy777bffTFhYmLnzzjudy0aNGmUkmfnz52frw+FwGGOMyczMNOnp6S7r/vjjD1OmTBnz2GOPOZedOHHCSDKjR4/O1tfo0aPN5f+Ek5KSjCTz+OOPu7QbNmyYkWRWrVrlXFalShUjyXzzzTfOZcnJycZut5uhQ4fmOgfGGLNw4UIjybz66qvOZZmZmaZVq1ZGkpkxY0auGd98800jyZw4cSLX/hMTE7P1c8ldd91lJJn33nsvx3V33XWX8/7q1auNJFOhQgWTmprqXP7ZZ58ZSWby5MnOZVWqVDExMTHX7PNq2WJiYkyVKlWc9y/N08svv+zS7oEHHjA2m83s3bvXuUySCQgIcFn2ww8/GEnmrbfeyrat/Ljy9ZSWlpatzbp164wk89FHHzmXzZ0710gyq1evzrHfVq1auczh/v37s81VTEyMkWReeukll8c2adLENGvWzHn/888/N5LMpEmTnMuysrJMmzZtcp1/AABuFPuB7AdaYT/w0r7Za6+9luP61157zUgy+/fvz3F9SEhIjvNkzP+e6xMnTphhw4aZmjVrOtf95S9/Mf369TPG/DnWgQMH5mscgDvxk0kgD7KysrRs2TJ1797d5ff05cqV06OPPqq1a9cqNTVVkvT555+rUaNG6tGjR7Z+Lh027uvr6zzXgcPh0KlTp5SZmanmzZtry5YtN5Rx8eLFkqTnnnvOZfnQoUMl/XnC88vVr1/f+e2WJJUqVUp16tTRL7/8cs3t+Pn5OY/muTSef/zjH9fMGBkZKUn64osv5HA4rtk+J3a7Xf369ctz+z59+igsLMx5/4EHHlC5cuWc8+Upixcvlq+vr5555hmX5UOHDpUxRkuWLHFZ3q5dO9WoUcN5PyoqSuHh4dd8PvLr8m9HMzIydPLkSdWsWVORkZF5fi2ePn1a69aty/M3f0899ZTL/VatWrmMc+nSpfL399cTTzzhXObj46OBAwfmqX8AANyJ/UDX7bAfeG03y36gJzz66KPau3evEhMTnf/l55IorCiIAXlw4sQJpaWlqU6dOtnW1atXTw6Hw3k+gn379qlhw4bX7PPDDz9UVFSUAgMDVaJECZUqVUpff/21UlJSbijjwYMH5ePjo5o1a7osL1u2rCIjI3Xw4EGX5ZUrV87WR7FixfTHH39cczvlypVTaGioy/Kc5uZKDz30kFq2bKnHH39cZcqU0cMPP6zPPvvsunaKKlSocF0nTq1Vq5bLfZvNppo1a171aonucPDgQZUvX95lJ0z6388M3fV8HDt2zOV2vVdzOn/+vEaNGuU8v0XJkiVVqlQpnT59Os+vxfj4eEnSPffcc822gYGBznOiXHLlOC+9xoKDg13aXfnaBmAd33zzjbp27ary5cvLZrNp4cKF192HMUYTJ05U7dq1ZbfbVaFCBY0bN879YVHksB/ouh32A6/tZtkPzMmV5327Xk2aNFHdunU1e/ZszZo1S2XLllWbNm3ynQvwBApigBf897//Vd++fVWjRg1Nnz5dS5cu1fLly9WmTZsb/sbskrz+EfP19c1xubniRJ/uFBQUpG+++UYrVqxQ7969tW3bNj300ENq3759tpOqX60Pd8ttzvKayR1u9PkoV66cy+3TTz+9ru3+4x//0Lhx4/Tggw/qs88+07Jly7R8+XKVKFEiz6/FxYsXq2XLloqIiLhm29zGCQBXc+7cOTVq1EjvvPPODfcxePBgffDBB5o4caJ+/PFHffnll7r11lvdmBLIG/YD2Q+8UkHsBwYGBkpSrkWztLQ0l3b58eijj+rTTz/V7Nmz9dBDD8nHh7IDCidOqg/kQalSpRQcHKw9e/ZkW/fjjz/Kx8dHlSpVkiTVqFFDO3bsuGp/8+bNU/Xq1TV//nyXP8KjR492aXc939BUqVJFDodDP//8s8vJzo8fP67Tp0+rSpUqee7rWttZuXKlzp496/LtYE5zkxMfHx+1bdtWbdu21RtvvKHx48frhRde0OrVq9WuXbt8fyt1pZ9//tnlvjFGe/fudTkpbbFixXK8OtLBgwddfhpxvc/HihUrdObMGZdvBy9ddcddz8fy5ctd7l/tRLg5mTdvnmJiYvT66687l124cCHbfOQ2dmOMli5dqmHDhl3Xdq+mSpUqWr16tfNS6pfs3bvXbdsAcHPp1KmTOnXqlOv69PR0vfDCC/rkk090+vRpNWzYUK+88orzCnG7d+/WlClTtGPHDueRLNWqVSuI6CgC2A903Q77gddWGPcDr/Y6lv58DoODg1WyZMl853r00Uc1atQoHT16VB9//HG++wM8hVItkAe+vr6655579MUXX7gcYn38+HHNnj1bd9xxh8LDwyVJ999/v3744YdsV/OR/vctz6VvgS7/1mfDhg1at26dS/tLxYCc/khfqXPnzpKkSZMmuSx/4403JMltV3bp3LmzMjMzNWXKFOeyrKwsvfXWW9d87KlTp7Ita9y4sSQ5LwkeEhIiKW9jzouPPvpIZ86ccd6fN2+ejh496vLBqkaNGlq/fr0uXrzoXLZo0aJsl+W+nmydO3dWVlaW3n77bZflb775pmw221U/2F2Pdu3audzKlSt3XY/39fXN9u3jW2+9le1b0dzGnpiYqOTkZLdeOahDhw7KyMjQtGnTnMscDke+jgwBULQNGjRI69at05w5c7Rt2zb17NlTHTt2dH4Y/uqrr1S9enUtWrRI1apVU9WqVfX444/n+HcJuBL7ga7bYT/w2tkK437gpdfxV199pUOHDrmsO3TokL766ivdc889bjmav0aNGpo0aZLi4uI4EheFGkeIAZf5z3/+o6VLl2ZbPnjwYL388stavny57rjjDj399NPy8/PT1KlTlZ6erldffdXZdvjw4Zo3b5569uypxx57TM2aNdOpU6f05Zdf6r333lOjRo107733av78+erRo4e6dOmi/fv367333lP9+vV19uxZZ19BQUGqX7++Pv30U9WuXVvFixdXw4YNczw3RaNGjRQTE6P3339fp0+f1l133aWNGzfqww8/VPfu3XX33Xe7ZY66du2qli1bauTIkTpw4IDq16+v+fPn5+mcFy+99JK++eYbdenSRVWqVFFycrLeffddVaxYUXfccYekP/+ARkZG6r333lNYWJhCQkJ022233fA3+cWLF9cdd9yhfv366fjx45o0aZJq1qzpcsL2xx9/XPPmzVPHjh314IMPat++ffrvf//rcnLT683WtWtX3X333XrhhRd04MABNWrUSMuWLdMXX3yhZ599Nlvf3nLvvffq448/VkREhOrXr69169ZpxYoV2S7x3bhxY/n6+uqVV15RSkqK7Ha72rRpo6+//lpVq1ZV/fr13Zape/fuuvXWWzV06FDt3btXdevW1Zdffunc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Zd566y3j6+trli5d6mwzZ84cExAQYP7zn/+YnTt3mieeeMJERkaa48eP5znL9fjyyy/N119/bX766SezZ88e889//tP4+/ubHTt2FOlxX27jxo2matWqJioqygwePDjP27tZxz569GjToEEDl89JJ06cKPLjPnXqlKlSpYrp27ev2bBhg/nll19MfHy82bt3r7NNUX2PS05Odnm+ly9fbiSZ1atXG2OK7nNujDHjxo0zJUqUMIsWLTL79+83c+fONaGhoWby5MnONkX1eb9SoSuIXe5qO9aXpKSkGElmxYoVxhhjMjIyTIUKFcwHH3xQAAm950bm5koXL140pUqVMi+99JIHEnrHjczLiRMnjCTzzTffONukpqYaSWb58uWejFugbmRupk6dakqXLm2ysrKcbbZt22YkmZ9//tmTcQtMbvPy66+/mgoVKpgdO3aYKlWquHyA37Vrl5FkEhMTncuWLFlibDabOXLkSAGkLhg3MjeXmzFjRpEpiF0uv/NyyauvvmqqVavmmZBe4q65+eKLL4zNZjMXL170TFDgBl35Gnc4HKZs2bLmtddecy47ffq0sdvt5pNPPjHG5O1vxrvvvmuKFStm0tPTnW1GjBhh6tSp47z/4IMPmi5durjkue2228zf//73PGfJj+TkZCPJrFmzxtm3v7+/mTt3rrPN7t27jSSzbt06Y8yfxUQfHx9z7NgxZ5spU6aY8PBw51iff/5506BBA5dtPfTQQ6ZDhw7O+7feeqsZOHCg835WVpYpX768iYuLy3OW/CpWrJj54IMPLDHuM2fOmFq1apnly5ebu+66y1kQK8pjHz16tGnUqFGO64ryuEeMGGHuuOOOXNdb6T1u8ODBpkaNGsbhcBTp59wYY7p06WIee+wxl2V//etfTa9evYwx1nreC91PJq/HxYsX9f777ysiIkKNGjWS9OfPu44cOSIfHx81adJE5cqVU6dOnbRjxw4vpy1YOc3Nlb788kudPHlS/fr1K+B03pPTvJQoUUJ16tTRRx99pHPnzikzM1NTp05V6dKl1axZMy8nLjg5zU16eroCAgLk4/O/t4qgoCBJ0tq1a72SsyA4HA717t1bw4cPV4MGDbKtX7dunSIjI9W8eXPnsnbt2snHxyfHn3AXJdeaG6u6kXlJSUlR8eLFPZzM+653bk6dOqVZs2apRYsW8vf3L4CE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\n"
          },
          "metadata": {}
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "#@title Train the model\n",
        "\n",
        "# Bind the catalog to the target (label) and data sets.\n",
        "\n",
        "# NOTE: it is possible to use separate catalogs for the target and the data\n",
        "# sets. For example, one may try to predict the rate of events above magnitude 4\n",
        "# while using (in the data sets) all earthquakes above magnitude 2.\n",
        "\n",
        "# The required catalog is a pandas DataFrame with the self-explanatory columns\n",
        "# `time` (in seconds since Epoch time), `longitude`, `latitude`, `depth` [km],\n",
        "# and `magnitude`. Additionally, add the columns `x_utm` and `y_utm` with an\n",
        "# appropriate UTM projection of `longitude` and `latitude`.\n",
        "\n",
        "with gin.unlock_config():\n",
        "  gin.bind_parameter('target_earthquakes.catalog', random_catalog)\n",
        "  gin.bind_parameter('RecentEarthquakesDataSet.catalog', random_catalog)\n",
        "  gin.bind_parameter('SeismicityRateDataSet.catalog', random_catalog)\n",
        "\n",
        "# The first epoch is usually much slower than the rest.\n",
        "history, model, factory = train_and_evaluate_cumulative_hazard(verbose=True)"
      ],
      "metadata": {
        "id": "FToHBFM0SU-Q",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "9753f64a-4632-49ec-d6de-f3122b5c01ca"
      },
      "execution_count": 16,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Creating features.\n",
            "Creating a model.\n",
            "Training the model.\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "  0%|          | 0/20 [00:00<?, ?it/s]WARNING:tensorflow:Calling GradientTape.gradient on a persistent tape inside its context is significantly less efficient than calling it outside the context (it causes the gradient ops to be recorded on the tape, leading to increased CPU and memory usage). Only call GradientTape.gradient inside the context if you actually want to trace the gradient in order to compute higher order derivatives.\n",
            "100%|██████████| 20/20 [06:29<00:00, 19.46s/it]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "fig, axs = plt.subplots(ncols=3, figsize=(20, 3))\n",
        "\n",
        "_ = axs[0].plot(history['train_loss'])\n",
        "_ = axs[0].set_title('Train loss')\n",
        "_ = axs[1].plot(history['validation_loss'])\n",
        "_ = axs[1].set_title('Validation loss')\n",
        "_ = axs[2].plot(history['test_loss'])\n",
        "_ = axs[2].set_title('Test loss')\n",
        "\n",
        "for ax in axs:\n",
        "  _ = ax.set_xlabel('Epoch')\n",
        "  _ = ax.set_ylabel('Minus Log-Likelihood (loss)')\n",
        "\n",
        "# It is not strange the the losses are on different scales - there's a different\n",
        "# number of examples (earthquakes) per segment of data."
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 333
        },
        "id": "sPFajVkL_8xL",
        "outputId": "1ba54f41-2ca4-4cbd-a93d-5e83b030e464"
      },
      "execution_count": 17,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<Figure size 2000x300 with 3 Axes>"
            ],
            "image/png": "iVBORw0KGgoAAAANSUhEUgAABlkAAAE8CAYAAABD8NexAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAC1JElEQVR4nOzdd3wVdfb/8ddN7wkJKQRC6ITQQhMCighIiw3ZtUVAlhVlgwq4/hC/6IKuwNpQFMGCgoVFULEggpGqEFogSO8kAVKAkE76/f0RuWsENAn35t4k7+fjMQ/3zsydOXPd3TmZM5/zMRiNRiMiIiIiIiIiIiIiIiJSJXbWDkBERERERERERERERKQ2UpFFRERERERERERERESkGlRkERERERERERERERERqQYVWURERERERERERERERKpBRRYREREREREREREREZFqUJFFRERERERERERERESkGlRkERERERERERERERERqQYVWURERERERERERERERKpBRRYREREREREREREREZFqUJFFRCzqoYceolmzZmY73oYNGzAYDGzYsMFsxxQREZGad+rUKQwGA4sWLTKtmz59OgaDoVLfNxgMTJ8+3awx9evXj379+pn1mJWh/EZERET+iHIFEdumIotIPWUwGCq16AYuIiIid9xxB25ubuTk5Fxzn+joaJycnLhw4UINRlZ1Bw4cYPr06Zw6dcraoYiIiIgNqcnnJPn5+UyfPl3PXETqCAdrByAi1vHxxx9X+PzRRx8RGxt7xfp27dpd13nee+89ysrKrusYIiIiYl3R0dF8++23rFixglGjRl2xPT8/n6+//pohQ4bg5+dX7fNMmzaNp59++npC/VMHDhxgxowZ9OvX74rRtj/88INFzy0iIiK2q6aek0B57jRjxgwAq4yiFRHzUpFFpJ568MEHK3zeunUrsbGxV6z/vfz8fNzc3Cp9HkdHx2rFJyIiIrbjjjvuwNPTkyVLlly1yPL111+Tl5dHdHT0dZ3HwcEBBwfr/Yni5ORktXOLiIiIdVX3OYmIiNqFicg19evXjw4dOhAfH0/fvn1xc3PjmWeeAcofpkRFRREcHIyzszMtW7bkhRdeoLS0tMIxfj8ny+X+66+88grvvvsuLVu2xNnZmR49erBjx45qx7p8+XK6deuGq6srDRs25MEHH+TMmTMV9klNTWXMmDE0adIEZ2dnGjVqxJ133lmhXcjOnTsZPHgwDRs2xNXVlebNm/O3v/2t2nGJiIjUBa6urtx9992sXbuW9PT0K7YvWbIET09P7rjjDjIyMvjnP/9Jx44d8fDwwMvLi6FDh7Jnz54/Pc/V5mQpLCxk0qRJ+Pv7m85x+vTpK76bmJjIP/7xD9q2bYurqyt+fn789a9/rXCfX7RoEX/9618BuOWWW65o+3G1OVnS09MZO3YsgYGBuLi40LlzZxYvXlxhH+U3IiIi9UNZWRmvv/467du3x8XFhcDAQB555BEuXrxYYb8/uveeOnUKf39/AGbMmGHKR6oz15xyBRHboJEsIvKHLly4wNChQ7nvvvt48MEHCQwMBMofUnh4eDB58mQ8PDxYt24dzz33HNnZ2bz88st/etwlS5aQk5PDI488gsFg4KWXXuLuu+/mxIkTVR79smjRIsaMGUOPHj2YNWsWaWlpvPHGG2zevJndu3fj4+MDwIgRI9i/fz+PPfYYzZo1Iz09ndjYWJKSkkyfBw0ahL+/P08//TQ+Pj6cOnWKL7/8ssq/m4iISF0THR3N4sWLWbZsGRMmTDCtz8jIYM2aNdx///24urqyf/9+vvrqK/7617/SvHlz0tLSeOedd7j55ps5cOAAwcHBVTrv3//+dz755BMeeOABevfuzbp164iKirpivx07drBlyxbuu+8+mjRpwqlTp5g/fz79+vXjwIEDuLm50bdvXx5//HHmzp3LM888Y2r3ca22H5cuXaJfv34cO3aMCRMm0Lx5c5YvX85DDz1EZmYmTzzxRIX9ld+IiIjUbY888ojpHv34449z8uRJ3nrrLXbv3s3mzZtxdHT803uvv78/8+fPZ/z48QwfPpy7774bgE6dOlUpFuUKIjbEKCJiNBpjYmKMv/+/hJtvvtkIGBcsWHDF/vn5+Vese+SRR4xubm7GgoIC07rRo0cbQ0NDTZ9PnjxpBIx+fn7GjIwM0/qvv/7aCBi//fbbP4xz/fr1RsC4fv16o9FoNBYVFRkDAgKMHTp0MF66dMm038qVK42A8bnnnjMajUbjxYsXjYDx5ZdfvuaxV6xYYQSMO3bs+MMYRERE6qOSkhJjo0aNjJGRkRXWL1iwwAgY16xZYzQajcaCggJjaWlphX1OnjxpdHZ2Nj7//PMV1gHGDz/80LTuX//6V4V8JCEhwQgY//GPf1Q43gMPPGAEjP/6179M666Wm8TFxRkB40cffWRat3z58gq5xG/dfPPNxptvvtn0+fXXXzcCxk8++cS0rqioyBgZGWn08PAwZmdnV7gW5TciIiJ1x++fk/z0009GwPjpp59W2G/16tUV1lfm3nvu3Lkrcpk/olxBxLapXZiI/CFnZ2fGjBlzxXpXV1fTf87JyeH8+fPcdNNN5Ofnc+jQoT897r333kuDBg1Mn2+66SYATpw4UaX4du7cSXp6Ov/4xz9wcXExrY+KiiIsLIzvvvvOFK+TkxMbNmy4YhjvZZff8li5ciXFxcVVikNERKSus7e357777iMuLq5Ce4klS5YQGBjIgAEDgPLcwc6u/M+M0tJSLly4gIeHB23btmXXrl1VOueqVasAePzxxyusnzhx4hX7/jY3KS4u5sKFC7Rq1QofH58qn/e35w8KCuL+++83rXN0dOTxxx8nNzeXjRs3Vthf+Y2IiEjdtXz5cry9vbn11ls5f/68aenWrRseHh6sX78eqJl7r3IFEduiIouI/KHGjRtfdRLY/fv3M3z4cLy9vfHy8sLf3980GVxWVtafHrdp06YVPl9+IHGtm/61JCYmAtC2bdsrtoWFhZm2Ozs785///Ifvv/+ewMBA+vbty0svvURqaqpp/5tvvpkRI0YwY8YMGjZsyJ133smHH35IYWFhlWISERGpqy5PbL9kyRIATp8+zU8//cR9992Hvb09UN6rfM6cObRu3RpnZ2caNmyIv78/v/zyS6VyhN9KTEzEzs6Oli1bVlh/tfv+pUuXeO655wgJCalw3szMzCqf97fnb926talodNnl9mKX84zLlN+IiIjUXUePHiUrK4uAgAD8/f0rLLm5uaZ562ri3qtcQcS2qMgiIn/ot2+FXpaZmcnNN9/Mnj17eP755/n222+JjY3lP//5D1D+cOXPXH4Q83tGo/H6Av4DEydO5MiRI8yaNQsXFxeeffZZ2rVrx+7duwEwGAx8/vnnxMXFMWHCBM6cOcPf/vY3unXrRm5ursXiEhERqS26detGWFgY//3vfwH473//i9FoNBVfAGbOnMnkyZPp27cvn3zyCWvWrCE2Npb27dtXKkeorscee4wXX3yRe+65h2XLlvHDDz8QGxuLn5+fRc/7W8pvRERE6q6ysjICAgKIjY296vL8888DtnfvVa4gYnkqsohIlW3YsIELFy6waNEinnjiCW677TYGDhxYoT1GTQkNDQXg8OHDV2w7fPiwaftlLVu25Mknn+SHH35g3759FBUV8eqrr1bYp1evXrz44ovs3LmTTz/9lP3797N06VLLXYSIiEgtEh0dzb59+/jll19YsmQJrVu3pkePHqbtn3/+ObfccgsLFy7kvvvuY9CgQQwcOJDMzMwqnys0NJSysjKOHz9eYf3V7vuff/45o0eP5tVXX+Uvf/kLt956KzfeeOMV5zUYDFU6/9GjR68o0lxujfr7PMNclN+IiIjYnpYtW3LhwgX69OnDwIEDr1g6d+5cYf8/uvdWJR+5GuUKIrZFRRYRqbLLb2n+9q3MoqIi3n777RqPpXv37gQEBLBgwYIKQ1m///57Dh48SFRUFAD5+fkUFBRU+G7Lli3x9PQ0fe/ixYtXvGkaEREBoGGyIiIiv7o8auW5554jISGhwigWKM8Tfn8/Xb58OWfOnKnyuYYOHQrA3LlzK6x//fXXr9j3aud98803KS0trbDO3d0doFJFn2HDhpGamspnn31mWldSUsKbb76Jh4cHN998c2Uuo8qU34iIiNiee+65h9LSUl544YUrtpWUlJhyi8rce93c3IDK5SNXo1xBxLY4WDsAEal9evfuTYMGDRg9ejSPP/44BoOBjz/+2KKtMK7F0dGR//znP4wZM4abb76Z+++/n7S0NN544w2aNWvGpEmTADhy5AgDBgzgnnvuITw8HAcHB1asWEFaWhr33XcfAIsXL+btt99m+PDhtGzZkpycHN577z28vLwYNmxYjV+biIiILWrevDm9e/fm66+/BriiyHLbbbfx/PPPM2bMGHr37s3evXv59NNPadGiRZXPFRERwf3338/bb79NVlYWvXv3Zu3atRw7duyKfW+77TY+/vhjvL29CQ8PJy4ujh9//BE/P78rjmlvb89//vMfsrKycHZ2pn///gQEBFxxzHHjxvHOO+/w0EMPER8fT7Nmzfj888/ZvHkzr7/+Op6enlW+pspQfiMiImJ7br75Zh555BFmzZpFQkICgwYNwtHRkaNHj7J8+XLeeOMN/vKXv1Tq3uvq6kp4eDifffYZbdq0wdfXlw4dOtChQ4dKxaJcQcS2qMgiIlXm5+fHypUrefLJJ5k2bRoNGjTgwQcfZMCAAQwePLjG43nooYdwc3Nj9uzZTJkyBXd3d4YPH85//vMffHx8AAgJCeH+++9n7dq1fPzxxzg4OBAWFsayZcsYMWIEUJ4wbd++naVLl5KWloa3tzc33HADn376Kc2bN6/x6xIREbFV0dHRbNmyhRtuuIFWrVpV2PbMM8+Ql5fHkiVL+Oyzz+jatSvfffcdTz/9dLXO9cEHH+Dv78+nn37KV199Rf/+/fnuu+8ICQmpsN8bb7yBvb09n376KQUFBfTp04cff/zxitwkKCiIBQsWMGvWLMaOHUtpaSnr16+/apHF1dWVDRs28PTTT7N48WKys7Np27YtH374IQ899FC1rqeylN+IiIjYngULFtCtWzfeeecdnnnmGRwcHGjWrBkPPvggffr0ASp/733//fd57LHHmDRpEkVFRfzrX/+qdJEFlCuI2BKD0RqvnouIiIiIiIiIiIiIiNRympNFRERERERERERERESkGlRkERERERERERERERERqQYVWURERERERERERERERKpBRRYREREREREREREREZFqsGqRZfr06RgMhgpLWFiYaXtBQQExMTH4+fnh4eHBiBEjSEtLq3CMpKQkoqKicHNzIyAggKeeeoqSkpKavhQREREREREREREREalnHKwdQPv27fnxxx9Nnx0c/hfSpEmT+O6771i+fDne3t5MmDCBu+++m82bNwNQWlpKVFQUQUFBbNmyhZSUFEaNGoWjoyMzZ86s8WsREREREREREREREZH6w2A0Go3WOvn06dP56quvSEhIuGJbVlYW/v7+LFmyhL/85S8AHDp0iHbt2hEXF0evXr34/vvvue222zh79iyBgYEALFiwgClTpnDu3DmcnJwqFUdZWRlnz57F09MTg8FgtusTERGpzYxGIzk5OQQHB2Nnpw6jlqRcRERE5ErKRWqOchEREZErVTYXsfpIlqNHjxIcHIyLiwuRkZHMmjWLpk2bEh8fT3FxMQMHDjTtGxYWRtOmTU1Flri4ODp27GgqsAAMHjyY8ePHs3//frp06XLVcxYWFlJYWGj6fObMGcLDwy13kSIiIrVYcnIyTZo0sXYYddrZs2cJCQmxdhgiIiI2SbmI5SkXERERubY/y0WsWmTp2bMnixYtom3btqSkpDBjxgxuuukm9u3bR2pqKk5OTvj4+FT4TmBgIKmpqQCkpqZWKLBc3n5527XMmjWLGTNmXLE+OTkZLy+v67wqERGRuiE7O5uQkBA8PT2tHUqdd/k3Vi4iIiLyP8pFao5yERERkStVNhexapFl6NChpv/cqVMnevbsSWhoKMuWLcPV1dVi5506dSqTJ082fb78Y3l5eSmZEBER+R21jLC8y7+xchEREZErKRexPOUiIiIi1/ZnuYhNNTX18fGhTZs2HDt2jKCgIIqKisjMzKywT1paGkFBQQAEBQWRlpZ2xfbL267F2dnZlDgogRAREam/5s+fT6dOnUz5QGRkJN9//z0AGRkZPPbYY7Rt2xZXV1eaNm3K448/TlZWVoVjJCUlERUVhZubGwEBATz11FOUlJRY43JEREREREREpIbZVJElNzeX48eP06hRI7p164ajoyNr1641bT98+DBJSUlERkYCEBkZyd69e0lPTzftExsbi5eXl+ZYERERkT/VpEkTZs+eTXx8PDt37qR///7ceeed7N+/n7Nnz3L27FleeeUV9u3bx6JFi1i9ejVjx441fb+0tJSoqCiKiorYsmULixcvZtGiRTz33HNWvCoRERERERERqSkGo9FotNbJ//nPf3L77bcTGhrK2bNn+de//kVCQgIHDhzA39+f8ePHs2rVKhYtWoSXlxePPfYYAFu2bAHKH2xEREQQHBzMSy+9RGpqKiNHjuTvf/87M2fOrHQc2dnZeHt7k5WVpVEtIiIiv6qv90dfX19efvnlCsWUy5YvX86DDz5IXl4eDg4OfP/999x2222cPXvWNC/cggULmDJlCufOncPJyalS56yvv7WIiMgf0f2x5ui3FhERuVJl749WHcly+vRp7r//ftq2bcs999yDn58fW7duxd/fH4A5c+Zw2223MWLECPr27UtQUBBffvml6fv29vasXLkSe3t7IiMjefDBBxk1ahTPP/+8tS5JREREaqnS0lKWLl1KXl6eadTs711OrBwcyqe1i4uLo2PHjqYCC8DgwYPJzs5m//791zxXYWEh2dnZFRYRERERERERqX2sOvH90qVL/3C7i4sL8+bNY968edfcJzQ0lFWrVpk7NBEREakn9u7dS2RkJAUFBXh4eLBixYqrth09f/48L7zwAuPGjTOtS01NrVBgAUyfU1NTr3nOWbNmMWPGDDNdgYiIiIiIiIhYi03NyVKXGI1Gysqs1olNREREKqlt27YkJCSwbds2xo8fz+jRozlw4ECFfbKzs4mKiiI8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TGIR3gpCREREREREREREREQ0BEyyEBERERERERERERERDQGTLCPAYDBg3bp1MBgM2T6VYZevbcvXdgFsmxrla7uA/G1bvraL1CuffyfztW352i6AbVOjfG0XkL9ty9d2kXrl8+8k26Y++douIH/blq/tAvK3bfnarkxx4nsiIiIiIiIiIiIiIqIhYCULERERERERERERERHREDDJQkRERERERERERERENARMshAREREREREREREREQ0BkyxERERERERERERERERDwCTLED355JOYNGkSjEYj5s2bh48//rjf7V966SWcc845MBqNmD17Nv73f/93lM40cxs2bMAll1wCq9UKh8OBJUuW4MiRI/3us3nzZkiSlPYwGo2jdMaZe+ihh3qc5znnnNPvPmros0mTJvVolyRJWLVqVa/b53J/vffee/jmN7+JqqoqSJKEV155JW29EAL/+q//isrKShQWFmLBggWora0d8LiD/Vsdbv21KxKJYM2aNZg9ezbMZjOqqqpwyy23oLGxsd9jDuX3eSQM1Ge33nprj/NctGjRgMfN5T4D0OvfnCRJ+MUvftHnMXOlzyi/MBaR5fK1LRVjEVku9xdjEcYiSbncZwBjEcodjEVkuXxtS8VYRJbL/cVYhLFIUi73GcBYpDdMsgzBH//4R9x///1Yt24d9u3bhzlz5mDhwoVwu929bv/BBx/g+9//Pu644w7s378fS5YswZIlS/D555+P8pn3b+fOnVi1ahU+/PBDbN26FZFIBNdccw38fn+/+9lsNpw+fVp5NDQ0jNIZD865556bdp7vv/9+n9uqpc/27NmT1qatW7cCAL773e/2uU+u9pff78ecOXPw5JNP9rr+5z//OX75y1/iqaeewkcffQSz2YyFCxciGAz2eczB/q2OhP7aFQgEsG/fPqxduxb79u3Dyy+/jCNHjuBb3/rWgMcdzO/zSBmozwBg0aJFaef5wgsv9HvMXO8zAGntOX36NDZt2gRJkrB06dJ+j5sLfUb5g7FIuly9tp2JsYgsV/uLsQhjESD3+wxgLEK5gbFIuly9tp2JsYgsV/uLsQhjESD3+wxgLNIrQYN26aWXilWrVik/x2IxUVVVJTZs2NDr9jfddJO47rrr0pbNmzdP/N3f/d2InufZcrvdAoDYuXNnn9s8++yzwm63j95JDdG6devEnDlzMt5erX127733iilTpoh4PN7rerX0FwCxZcsW5ed4PC4qKirEL37xC2VZR0eHMBgM4oUXXujzOIP9Wx1pZ7arNx9//LEAIBoaGvrcZrC/z6Oht7atWLFC3HDDDYM6jhr77IYbbhBXXXVVv9vkYp+RujEW6aaWaxtjEZla+ouxCGORJDX0GWMRygbGIt3Ucm1jLCJTS38xFmEskqSGPmMsIgQrWQYpHA5j7969WLBggbJMo9FgwYIF2L17d6/77N69O217AFi4cGGf2+eKzs5OAEBJSUm/2/l8PlRXV2PChAm44YYbcPDgwdE4vUGrra1FVVUVJk+ejOXLl+PEiRN9bqvGPguHw/j973+P22+/HZIk9bmdWvorVX19PZqamtL6xG63Y968eX32yVD+VnNBZ2cnJElCUVFRv9sN5vc5m3bs2AGHw4EZM2Zg5cqVaG1t7XNbNfaZy+XCG2+8gTvuuGPAbdXSZ5T7GIv0pJZrG2MRmVr6KxVjkZ7Ucl1jLNJNLX1GuY+xSE9qubYxFpGppb9SMRbpSS3XNcYi3dTSZ0PBJMsgtbS0IBaLwel0pi13Op1oamrqdZ+mpqZBbZ8L4vE47rvvPlx++eU477zz+txuxowZ2LRpE1599VX8/ve/Rzwex2WXXYavvvpqFM92YPPmzcPmzZvx1ltvYePGjaivr8eVV14Jr9fb6/Zq7LNXXnkFHR0duPXWW/vcRi39dabk5z6YPhnK32q2BYNBrFmzBt///vdhs9n63G6wv8/ZsmjRIvzud7/D9u3b8dhjj2Hnzp1YvHgxYrFYr9ursc+ee+45WK1W3Hjjjf1up5Y+I3VgLJJOLdc2xiIytfTXmRiLpFPLdY2xSDe19BmpA2ORdGq5tjEWkamlv87EWCSdWq5rjEW6qaXPhkqb7ROg3LRq1Sp8/vnnA46NN3/+fMyfP1/5+bLLLsPMmTPx9NNP4+GHHx7p08zY4sWLldfnn38+5s2bh+rqavzpT3/KKNOqBs888wwWL16MqqqqPrdRS3+NRZFIBDfddBOEENi4cWO/26rl93nZsmXK69mzZ+P888/HlClTsGPHDlx99dVZPLPhs2nTJixfvnzAiRLV0mdEuYSxiPowFlE3xiLqxFiEaOQwFlEfxiLqxlhEnRiLyFjJMkhlZWUoKCiAy+VKW+5yuVBRUdHrPhUVFYPaPttWr16N119/He+++y7Gjx8/qH11Oh0uvPBC1NXVjdDZDY+ioiJMnz69z/NUW581NDRg27Zt+MEPfjCo/dTSX8nPfTB9MpS/1WxJBhINDQ3YunVrv3dr9Gag3+dcMXnyZJSVlfV5nmrqMwD4v//7Pxw5cmTQf3eAevqMchNjkf6p5drGWESmlv5iLNI/tVzXGIt0U0ufUW5iLNI/tVzbGIvI1NJfjEX6p5brGmORbmrps0wxyTJIer0ec+fOxfbt25Vl8Xgc27dvT8uEp5o/f37a9gCwdevWPrfPFiEEVq9ejS1btuCdd95BTU3NoI8Ri8Vw4MABVFZWjsAZDh+fz4djx471eZ5q6bOkZ599Fg6HA9ddd92g9lNLf9XU1KCioiKtTzweDz766KM++2Qof6vZkAwkamtrsW3bNpSWlg76GAP9PueKr776Cq2trX2ep1r6LOmZZ57B3LlzMWfOnEHvq5Y+o9zEWKR/arm2MRaRqaW/GIv0Ty3XNcYi3dTSZ5SbGIv0Ty3XNsYiMrX0F2OR/qnlusZYpJta+ixjggbtxRdfFAaDQWzevFkcOnRI3HnnnaKoqEg0NTUJIYS4+eabxT/90z8p2+/atUtotVrx7//+7+Lw4cNi3bp1QqfTiQMHDmSrCb1auXKlsNvtYseOHeL06dPKIxAIKNuc2bb169eLt99+Wxw7dkzs3btXLFu2TBiNRnHw4MFsNKFPDzzwgNixY4eor68Xu3btEgsWLBBlZWXC7XYLIdTbZ0IIEYvFxMSJE8WaNWt6rFNTf3m9XrF//36xf/9+AUA8/vjjYv/+/aKhoUEIIcSjjz4qioqKxKuvvir+8pe/iBtuuEHU1NSIrq4u5RhXXXWV+NWvfqX8PNDfarbbFQ6Hxbe+9S0xfvx48emnn6b93YVCoT7bNdDvcy60zev1igcffFDs3r1b1NfXi23btomLLrpITJs2TQSDwT7blut9ltTZ2SlMJpPYuHFjr8fI1T6j/MFYRB3XtlSMRWS53F+MRRiLCJH7fZbEWISyjbGIOq5tqRiLyHK5vxiLMBYRIvf7LImxSDomWYboV7/6lZg4caLQ6/Xi0ksvFR9++KGy7q/+6q/EihUr0rb/05/+JKZPny70er0499xzxRtvvDHKZzwwAL0+nn32WWWbM9t23333KZ+D0+kU1157rdi3b9/on/wAvve974nKykqh1+vFuHHjxPe+9z1RV1enrFdrnwkhxNtvvy0AiCNHjvRYp6b+evfdd3v9/UuefzweF2vXrhVOp1MYDAZx9dVX92hzdXW1WLduXdqy/v5WR0N/7aqvr+/z7+7dd9/ts10D/T7nQtsCgYC45pprRHl5udDpdKK6ulr88Ic/7BEUqK3Pkp5++mlRWFgoOjo6ej1GrvYZ5RfGIrJcvralYiwiy+X+YizCWCQpl/ssibEI5QLGIrJcvralYiwiy+X+YizCWCQpl/ssibFIOkkIIXopcCEiIiIiIiIiIiIiIqJ+cE4WIiIiIiIiIiIiIiKiIWCShYiIiIiIiIiIiIiIaAiYZCEiIiIiIiIiIiIiIhoCJlmIiIiIiIiIiIiIiIiGgEkWIiIiIiIiIiIiIiKiIWCShYiIiIiIiIiIiIiIaAiYZCEiIiIiIiIiIiIiIhoCJlmIiIiIiIiIiIiIiIiGgEkWIsoLkiThlVdeyfZpEBER0RjFWISIiIiyibEIUfYwyUJEZ+3WW2+FJEk9HosWLcr2qREREdEYwFiEiIiIsomxCNHYps32CRBRfli0aBGeffbZtGUGgyFLZ0NERERjDWMRIiIiyibGIkRjFytZiGhYGAwGVFRUpD2Ki4sByCWrGzduxOLFi1FYWIjJkyfjf/7nf9L2P3DgAK666ioUFhaitLQUd955J3w+X9o2mzZtwrnnnguDwYDKykqsXr06bX1LSwu+/e1vw2QyYdq0aXjttddGttFERESUMxiLEBERUTYxFiEau5hkIaJRsXbtWixduhSfffYZli9fjmXLluHw4cMAAL/fj4ULF6K4uBh79uzBSy+9hG3btqUFCxs3bsSqVatw55134sCBA3jttdcwderUtPdYv349brrpJvzlL3/Btddei+XLl6OtrW1U20lERES5ibEIERERZRNjEaI8JoiIztKKFStEQUGBMJvNaY+f/exnQgghAIi77rorbZ958+aJlStXCiGE+O1vfyuKi4uFz+dT1r/xxhtCo9GIpqYmIYQQVVVV4l/+5V/6PAcA4ic/+Ynys8/nEwDEm2++OWztJCIiotzEWISIiIiyibEI0djGOVmIaFh84xvfwMaNG9OWlZSUKK/nz5+ftm7+/Pn49NNPAQCHDx/GnDlzYDablfWXX3454vE4jhw5AkmS0NjYiKuvvrrfczj//POV12azGTabDW63e6hNIiIiIhVhLEJERETZxFiEaOxikoWIhoXZbO5RpjpcCgsLM9pOp9Ol/SxJEuLx+EicEhEREeUYxiJERESUTYxFiMYuzslCRKPiww8/7PHzzJkzAQAzZ87EZ599Br/fr6zftWsXNBoNZsyYAavVikmTJmH79u2jes5ERESUPxiLEBERUTYxFiHKX6xkIaJhEQqF0NTUlLZMq9WirKwMAPDSSy/h4osvxhVXXIE//OEP+Pjjj/HMM88AAJYvX45169ZhxYoVeOihh9Dc3Ix77rkHN998M5xOJwDgoYcewl133QWHw4HFixfD6/Vi165duOeee0a3oURERJSTGIsQERFRNjEWIRq7mGQhomHx1ltvobKyMm3ZjBkz8MUXXwAA1q9fjxdffBF33303Kisr8cILL2DWrFkAAJPJhLfffhv33nsvLrnkEphMJixduhSPP/64cqwVK1YgGAziP//zP/Hggw+irKwM3/nOd0avgURERJTTGIsQERFRNjEWIRq7JCGEyPZJEFF+kyQJW7ZswZIlS7J9KkRERDQGMRYhIiKibGIsQpTfOCcLERERERERERERERHREDDJQkRERERERERERERENAQcLoyIiIiIiIiIiIiIiGgIWMlCREREREREREREREQ0BEyyEBERERERERERERERDQGTLEREREREREREREREREPAJAsREREREREREREREdEQMMlCREREREREREREREQ0BEyyEBERERERERERERERDQGTLEREREREREREREREREPAJAsREREREREREREREdEQ/H+zBDBW7hFwEgAAAABJRU5ErkJggg==\n"
          },
          "metadata": {}
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "#@title An example of how to use the model - showing the temporal hazard for different times after a mainshock\n",
        "\n",
        "space_times = (\n",
        "      EvaluationSpaceTimes.init_with_earthquake_times_and_locations()\n",
        ")\n",
        "features = factory.build_features(\n",
        "    space_times=space_times, training=False).to_flat_partial()\n",
        "order = cumulative_hazard_inputs_order([ds for ds in features.train_data])\n",
        "\n",
        "one_example = {ds: features.test_data[ds][0:1] for ds in order}\n",
        "new_features = {ds: [] for ds in order}\n",
        "delta_times = np.arange(1000, 100000, 100)\n",
        "for delta_time in delta_times:\n",
        "  for ds in order:\n",
        "    if ds == 'delta_time':\n",
        "      new_features[ds].append(np.array([[delta_time]]))\n",
        "    else:\n",
        "      new_features[ds].append(one_example[ds])\n",
        "features_with_new_delta_times = {}\n",
        "for ds in order:\n",
        "  features_with_new_delta_times[ds] = np.concatenate(new_features[ds], axis=0)\n",
        "\n",
        "output = get_model_output(\n",
        "    model, order, features_with_new_delta_times, side_deg ** 2)\n",
        "hazard = output.hazard\n",
        "\n",
        "_ = plt.plot(delta_times, hazard)\n",
        "_ = plt.xlabel('Time after mainshock (sec)')\n",
        "_ = plt.ylabel('Hazard')\n",
        "_ = plt.title('Hazard after a mainshock')"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 472
        },
        "cellView": "form",
        "id": "RlTra0MVjLrb",
        "outputId": "f53cbac8-f0a2-458d-a885-8546e6547807"
      },
      "execution_count": 18,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<Figure size 640x480 with 1 Axes>"
            ],
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlUAAAHHCAYAAACWQK1nAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABq8UlEQVR4nO3deVxU5f4H8M/MwMywzSAiDCAC5q64BIrYgimJiRnVdeFniWZppl3JypvlkmVRmmWW6bVFvfe6t1iZWoSmpYj7vqYoZg6IyLAoDMw8vz+QIyOggAMzwOf9es1rmOd855znnLE7n/uc55yRCSEEiIiIiOiuyG3dASIiIqKGgKGKiIiIyAoYqoiIiIisgKGKiIiIyAoYqoiIiIisgKGKiIiIyAoYqoiIiIisgKGKiIiIyAoYqoiIiIisgKGKiOrM0qVLIZPJcO7cOautc/fu3ejVqxdcXFwgk8lw4MABq627oTl37hxkMhmWLl1aK+sv/Xz37NlTK+uvzMiRI+Hq6lqn2ySqCEMVkR2605dT79690alTpzrulf0pKirC4MGDkZWVhY8++gj//e9/ERAQgM8++6zWggMRUWUcbN0BIqKaOnPmDM6fP4/PP/8czz77rNT+2WefwdPTEyNHjrRd5+xQQEAArl+/DkdHR1t3hahB4kgVEVmN2WxGQUFBnW0vIyMDAODu7l7r2youLobRaKz17dQmmUwGtVoNhUJh664QNUgMVUQNxJIlS9CnTx94eXlBpVKhQ4cOWLhwoUXNm2++CZlMVuGj7KjOBx98gF69eqFp06ZwcnJCSEgIvv7663LblMlkmDBhApYvX46OHTtCpVJh06ZNAICjR4+iT58+cHJyQvPmzTFr1iyYzeYq7cuhQ4cwcuRItGzZEmq1GjqdDs888wyuXLki1YwcORIREREAgMGDB0Mmk6F3794IDAzE0aNHsXXrVmnfevfuLb0vOzsb8fHx8Pf3h0qlQqtWrfD+++9b9K107tEHH3yAefPm4Z577oFKpcKxY8fu6vhXpnROUFpaGgYOHAhXV1f4+flhwYIFAIDDhw+jT58+cHFxQUBAAFasWGHx/qysLLzyyisIDg6Gq6srNBoNHnnkERw8eNCirqI5VaXbvnjxImJiYuDq6opmzZrhlVdegclksnj/qlWrEBISAjc3N2g0GgQHB+Pjjz8utz+FhYWYNGkSmjVrBhcXFzz++OO4fPlyubrPPvtM+nfj6+uL8ePHIzs7u1xdSkoKBgwYgCZNmsDFxQWdO3eucLtlHThwAM2aNUPv3r2Rl5d321oia+HpPyI7ZjAYkJmZWa69qKioXNvChQvRsWNHDBo0CA4ODvjxxx/xwgsvwGw2Y/z48QCAJ554Aq1atbJ43969ezFv3jx4eXlJbR9//DEGDRqE4cOHw2g0YtWqVRg8eDDWr1+P6Ohoi/dv3rwZa9aswYQJE+Dp6YnAwEDo9Xo89NBDKC4uxmuvvQYXFxcsXrwYTk5OVdrvxMREnD17FqNGjYJOp8PRo0exePFiHD16FDt37oRMJsPYsWPh5+eHd999F//85z/RvXt3eHt7Iz8/Hy+++CJcXV3xxhtvAAC8vb0BANeuXUNERAQuXryIsWPHokWLFtixYwemTJmCS5cuYd68eRb9WLJkCQoKCjBmzBioVCp4eHhU2ueqHP/bMZlMeOSRR/Dggw9i9uzZWL58OSZMmAAXFxe88cYbGD58OJ544gksWrQII0aMQHh4OIKCggAAZ8+exbp16zB48GAEBQUhPT0d//73vxEREYFjx47B19f3jtuOiopCWFgYPvjgA/z666+YO3cu7rnnHowbN076TGJjY9G3b1+8//77AIDjx49j+/btmDhxosX6XnzxRTRp0gQzZszAuXPnMG/ePEyYMAGrV6+Wat58803MnDkTkZGRGDduHE6ePImFCxdi9+7d2L59u3SKMjExEQMHDoSPjw8mTpwInU6H48ePY/369eW2W2r37t2IiopCaGgovv/++yr/uyO6a4KI7M6SJUsEgNs+OnbsaPGea9eulVtPVFSUaNmyZaXbuXz5smjRooUIDg4WeXl5la7LaDSKTp06iT59+li0AxByuVwcPXrUoj0+Pl4AECkpKVJbRkaG0Gq1AoBITU297f5XtC8rV64UAMS2bdukti1btggAYu3atRa1HTt2FBEREeXW8fbbbwsXFxdx6tQpi/bXXntNKBQKkZaWJoQQIjU1VQAQGo1GZGRk3Lavt+vznY5/qbi4OAFAvPvuu1Lb1atXhZOTk5DJZGLVqlVS+4kTJwQAMWPGDKmtoKBAmEwmi3WmpqYKlUol3nrrLYs2AGLJkiXltl22TgghunXrJkJCQqTXEydOFBqNRhQXF1e6H6X/biMjI4XZbJbaX3rpJaFQKER2drYQouTfglKpFP369bPo96effioAiK+++koIIURxcbEICgoSAQEB4urVqxbbKrv+uLg44eLiIoQQ4o8//hAajUZER0eLgoKCSvtKVBt4+o/Iji1YsACJiYnlHp07dy5XW/b/jZeOcEVERODs2bMwGAzl6k0mE2JjY5Gbm4vvvvsOLi4uFa7r6tWrMBgMeOCBB7Bv375y64mIiECHDh0s2jZs2ICePXuiR48eUluzZs0wfPjwKu132e0XFBQgMzMTPXv2BIAK+1BVa9euxQMPPIAmTZogMzNTekRGRsJkMmHbtm0W9U8++SSaNWtW7T5X5fhXpOxke3d3d7Rt2xYuLi4YMmSI1N62bVu4u7vj7NmzUptKpYJcXvI/5yaTCVeuXIGrqyvatm1b5eP1/PPPW7x+4IEHLLbh7u6O/Px8JCYm3nFdY8aMgUwms1iXyWTC+fPnAQC//vorjEYj4uPjpX4DwHPPPQeNRoOffvoJALB//36kpqYiPj6+3Ly5susvtWXLFkRFRaFv37749ttvoVKp7rzjRFbE039EdqxHjx4IDQ0t114aCsravn07ZsyYgeTkZFy7ds1imcFggFartWibOnUqNm/ejJ9++gn33HOPxbL169dj1qxZOHDgAAoLC6X2ir7ISk9BlXX+/HmEhYWVa2/btm0Fe1leVlYWZs6ciVWrVkmT0cvuS02dPn0ahw4dqjQo3bqtivatMtU9/rdSq9Xl+qXVatG8efNyx12r1eLq1avSa7PZjI8//hifffYZUlNTLeZCNW3a9I59r2jbTZo0sdjGCy+8gDVr1uCRRx6Bn58f+vXrhyFDhqB///7l1teiRYty6wIgra80XN3670GpVKJly5bS8jNnzgBAlW4fUlBQgOjoaISEhGDNmjVwcODXG9U9/qsjagDOnDmDvn37ol27dvjwww/h7+8PpVKJDRs24KOPPio3QXzdunV4//338fbbb5f7Uvz9998xaNAgPPjgg/jss8/g4+MDR0dHLFmypNwEaQC1Ml9lyJAh2LFjB1599VV07doVrq6uMJvN6N+/f5Unu1fEbDbj4YcfxuTJkytc3qZNG4vXVd236h7/ilR2RV5l7UII6e93330X06ZNwzPPPIO3334bHh4ekMvliI+Pv6ttl+Xl5YUDBw7g559/xsaNG7Fx40YsWbIEI0aMwLJly6rdZ2tTqVQYMGAAvv/+e2zatAkDBw6stW0RVYahiqgB+PHHH1FYWIgffvjBYpRgy5Yt5WpPnTqFuLg4xMTE4PXXXy+3/JtvvoFarcbPP/9scfpkyZIlVe5PQEAATp8+Xa795MmTd3zv1atXkZSUhJkzZ2L69OlSe0Xrq0xFI2oAcM899yAvLw+RkZFVXldVVOf414avv/4aDz30EL788kuL9uzsbHh6elptO0qlEo8++igeffRRmM1mvPDCC/j3v/+NadOmlbsA4nYCAgIAlPx7aNmypdRuNBqRmpoqfT6lI6hHjhy542cmk8mwfPlyPPbYYxg8eDA2btxocdUnUV3gnCqiBqB0ZKDsSIDBYCgXhPLy8vD444/Dz88Py5YtqzB8KBQKyGQyi1NI586dw7p166rcnwEDBmDnzp3YtWuX1Hb58mUsX768RvsCoNyVebfj4uJS4aX5Q4YMQXJyMn7++edyy7Kzs1FcXFzlbZRV1eNfWxQKRbnjtXbtWly8eNFq2yh7OwsAkMvl0ty+sqeIqyIyMhJKpRLz58+36PeXX34Jg8EgXWF67733IigoCPPmzSv3eVY06qVUKvHtt9+ie/fuePTRRy3+/RHVBY5UETUA/fr1k0YRxo4di7y8PHz++efw8vLCpUuXpLqZM2fi2LFjmDp1Kr7//nuLddxzzz0IDw9HdHQ0PvzwQ/Tv3x//93//h4yMDCxYsACtWrXCoUOHqtSfyZMn47///S/69++PiRMnSrdUCAgIuOM6NBqNdFuBoqIi+Pn54ZdffkFqamqVj0dISAgWLlyIWbNmoVWrVvDy8kKfPn3w6quv4ocffsDAgQMxcuRIhISEID8/H4cPH8bXX3+Nc+fO1Whkp6rHv7YMHDgQb731FkaNGoVevXrh8OHDWL58ucUo0N169tlnkZWVhT59+qB58+Y4f/48PvnkE3Tt2hXt27ev1rqaNWuGKVOmYObMmejfvz8GDRqEkydP4rPPPkP37t3x1FNPASgJbgsXLsSjjz6Krl27YtSoUfDx8cGJEydw9OjRCsOxk5MT1q9fjz59+uCRRx7B1q1b+ZNOVHdsd+EhEVWm9NL03bt3V7g8IiKi3C0VfvjhB9G5c2ehVqtFYGCgeP/998VXX31lcQuD0svnK3rExcVJ6/ryyy9F69athUqlEu3atRNLliwRM2bMELf+TwYAMX78+Ar7eOjQIRERESHUarXw8/MTb7/9tvjyyy+rdEuFv/76Szz++OPC3d1daLVaMXjwYPH333+Xu5VAZbdU0Ov1Ijo6Wri5uQkAFrdXyM3NFVOmTBGtWrUSSqVSeHp6il69eokPPvhAGI1GIcTNWw/MmTPntv0sqyrHvzJlbwlQVkWfsxBCBAQEiOjoaOl1QUGBePnll4WPj49wcnIS9913n0hOThYREREW+17ZLRUq2vatn/fXX38t+vXrJ7y8vIRSqRQtWrQQY8eOFZcuXZJqKvt3W/o5bdmyxaL9008/Fe3atROOjo7C29tbjBs3rtytE4QouU3Cww8/LNzc3ISLi4vo3Lmz+OSTT267D5mZmaJDhw5Cp9OJ06dPl1snUW2QCVGLMweJiIiIGgnOqSIiIiKyAoYqIiIiIitgqCIiIiKyAoYqIiIiIiuwi1C1YMECBAYGQq1WIyws7I73Flm7di3atWsHtVqN4OBgbNiwwWK5EALTp0+Hj48PnJycEBkZWe7Gge+88w569eoFZ2fncr8pBQAHDx5EbGws/P394eTkhPbt2+Pjjz++630lIiKihsnmoWr16tWYNGkSZsyYgX379qFLly6Iiooq9xtcpXbs2IHY2FiMHj0a+/fvR0xMDGJiYnDkyBGpZvbs2Zg/fz4WLVqElJQUuLi4ICoqCgUFBVKN0WjE4MGDMW7cuAq3s3fvXnh5eeF///sfjh49ijfeeANTpkzBp59+at0DQERERA2CzW+pEBYWhu7du0thxWw2w9/fHy+++CJee+21cvVDhw5Ffn4+1q9fL7X17NkTXbt2xaJFiyCEgK+vL15++WW88sorAErubOzt7Y2lS5di2LBhFutbunQp4uPjK7z78q3Gjx+P48ePY/PmzVXaN7PZjL///htubm6V/mwGERER2RchBHJzc+Hr6wu5vOrjTza9o7rRaMTevXsxZcoUqU0ulyMyMhLJyckVvic5ORmTJk2yaIuKipJ+QiM1NRV6vd7id6K0Wi3CwsKQnJxcLlRVh8FggIeHR6XLCwsLLX6u4eLFi+jQoUONt0dERES2c+HCBTRv3rzK9TYNVZmZmTCZTPD29rZo9/b2xokTJyp8j16vr7Ber9dLy0vbKqupiR07dmD16tX46aefKq1JSEjAzJkzy7VfuHABGo2mxtsmIiKiupOTkwN/f3+4ublV63387b8qOHLkCB577DHMmDED/fr1q7RuypQpFqNopR+KRqNhqCIiIqpnqjt1x6YT1T09PaFQKJCenm7Rnp6eDp1OV+F7dDrdbetLn6uzzts5duwY+vbtizFjxmDq1Km3rVWpVFKAYpAiIiJqXGwaqpRKJUJCQpCUlCS1mc1mJCUlITw8vML3hIeHW9QDQGJiolQfFBQEnU5nUZOTk4OUlJRK11mZo0eP4qGHHkJcXBzeeeedar2XiIiIGhebn/6bNGkS4uLiEBoaih49emDevHnIz8/HqFGjAAAjRoyAn58fEhISAAATJ05EREQE5s6di+joaKxatQp79uzB4sWLAZQM1cXHx2PWrFlo3bo1goKCMG3aNPj6+iImJkbablpaGrKyspCWlgaTyYQDBw4AAFq1agVXV1ccOXIEffr0QVRUFCZNmiTNx1IoFGjWrFndHSAiIiKqH4Qd+OSTT0SLFi2EUqkUPXr0EDt37pSWRUREiLi4OIv6NWvWiDZt2gilUik6duwofvrpJ4vlZrNZTJs2TXh7ewuVSiX69u0rTp48aVETFxcnAJR7bNmyRQghxIwZMypcHhAQUOX9MhgMAoAwGAzVOh5ERERkOzX9/rb5faoaspycHGi1WhgMBs6vIiIiqidq+v1t8zuqExERETUEDFVEREREVsBQRURERGQFDFVEREREVsBQRURERGQFDFVEREREVsBQRURERGQFNr+jOlVfRm4BCovMaOamgtpRYevuEBEREThSVS8NXpSMB2ZvwdG/DbbuChEREd3AUFUPKRUlH1thsdnGPSEiIqJSDFX1kOONUFVk4i8MERER2QuGqnpI6VDysRk5UkVERGQ3GKrqIYYqIiIi+8NQVQ8ppdN/DFVERET2gqGqHuJIFRERkf1hqKqHHBUyAICRI1VERER2g6GqHlI6lNzwkyNVRERE9oOhqh4qnVPFkSoiIiL7wVBVDykdSk7/FXGkioiIyG4wVNVDHKkiIiKyPwxV9RCv/iMiIrI/DFX1kCNHqoiIiOwOQ1U9xJEqIiIi+8NQVQ858o7qREREdoehqh5ScaSKiIjI7jBU1UPS6T+OVBEREdkNhqp6SJqoXixs3BMiIiIqxVBVD/E+VURERPaHoaoecrxx+o93VCciIrIfDFX1EEeqiIiI7A9DVT3Eq/+IiIjsD0NVPcT7VBEREdkfhqp6iHdUJyIisj8MVfVQaagqZKgiIiKyGwxV9ZCjQgaAp/+IiIjsCUNVPaTiHdWJiIjsjs1D1YIFCxAYGAi1Wo2wsDDs2rXrtvVr165Fu3btoFarERwcjA0bNlgsF0Jg+vTp8PHxgZOTEyIjI3H69GmLmnfeeQe9evWCs7Mz3N3dK9zOP//5T4SEhEClUqFr1653s4tWJ01U5+k/IiIiu2HTULV69WpMmjQJM2bMwL59+9ClSxdERUUhIyOjwvodO3YgNjYWo0ePxv79+xETE4OYmBgcOXJEqpk9ezbmz5+PRYsWISUlBS4uLoiKikJBQYFUYzQaMXjwYIwbN+62/XvmmWcwdOhQ6+ysFfG3/4iIiOyPTAhhsx+QCwsLQ/fu3fHpp58CAMxmM/z9/fHiiy/itddeK1c/dOhQ5OfnY/369VJbz5490bVrVyxatAhCCPj6+uLll1/GK6+8AgAwGAzw9vbG0qVLMWzYMIv1LV26FPHx8cjOzq60j2+++SbWrVuHAwcOVHv/cnJyoNVqYTAYoNFoqv3+ylzJK0TIrF8BAGffHQC5XGa1dRMRETV2Nf3+ttlIldFoxN69exEZGXmzM3I5IiMjkZycXOF7kpOTLeoBICoqSqpPTU2FXq+3qNFqtQgLC6t0ndZUWFiInJwci0dtKP2ZGgAoMnO0ioiIyB7YLFRlZmbCZDLB29vbot3b2xt6vb7C9+j1+tvWlz5XZ53WlJCQAK1WKz38/f1rZTulP1MD8F5VRERE9sLmE9UbkilTpsBgMEiPCxcu1Mp2GKqIiIjsj81ClaenJxQKBdLT0y3a09PTodPpKnyPTqe7bX3pc3XWaU0qlQoajcbiURvkchkc5KX3qrLZlDgiIiIqw2ahSqlUIiQkBElJSVKb2WxGUlISwsPDK3xPeHi4RT0AJCYmSvVBQUHQ6XQWNTk5OUhJSal0nfUVf6qGiIjIvjjYcuOTJk1CXFwcQkND0aNHD8ybNw/5+fkYNWoUAGDEiBHw8/NDQkICAGDixImIiIjA3LlzER0djVWrVmHPnj1YvHgxAEAmkyE+Ph6zZs1C69atERQUhGnTpsHX1xcxMTHSdtPS0pCVlYW0tDSYTCbpyr5WrVrB1dUVAPDnn38iLy8Per0e169fl2o6dOgApVJZNwfoNpQOclwzmmA0mWzdFSIiIoKNQ9XQoUNx+fJlTJ8+HXq9Hl27dsWmTZukieZpaWmQy28OpvXq1QsrVqzA1KlT8frrr6N169ZYt24dOnXqJNVMnjwZ+fn5GDNmDLKzs3H//fdj06ZNUKvVUs306dOxbNky6XW3bt0AAFu2bEHv3r0BAM8++yy2bt1ariY1NRWBgYFWPxbVVXpX9YIijlQRERHZA5vep6qhq637VAFAxJwtOH/lGr4ZF46QAA+rrpuIiKgxq3f3qaK7UzpSVciRKiIiIrvAUFVPqR0VAICCYs6pIiIisgcMVfUU51QRERHZF4aqeqp0pKqQI1VERER2gaGqnlI53Dj9x5EqIiIiu8BQVU+pHEsnqnOkioiIyB4wVNVT6tKRKt5RnYiIyC4wVNVTN0eqGKqIiIjsAUNVPXVzpIqn/4iIiOwBQ1U9xZEqIiIi+8JQVU9xpIqIiMi+MFTVUxypIiIisi8MVfWUuvSO6hypIiIisgsMVfWUqvSO6rxPFRERkV1gqKqn1KWn/3ifKiIiIrvAUFVP3fyZGo5UERER2QOGqnqKI1VERET2haGqnlJzpIqIiMiuMFTVUyqOVBEREdkVhqp6inOqiIiI7AtDVT3FOVVERET2haGqnuJIFRERkX1hqKqnys6pEkLYuDdERETEUFVPqW/cUV0IwGjiKUAiIiJbY6iqp1QONz+6Av6oMhERkc0xVNVTSoUcCrkMAOdVERER2QOGqnpKJpPB6cYpwGtGhioiIiJbY6iqx5yUpaGq2MY9ISIiIoaqesxZydsqEBER2QuGqnqMp/+IiIjsB0NVPXbz9B9DFRERka0xVNVjPP1HRERkPxiq6jEnRwcAHKkiIiKyBwxV9RhP/xEREdkPhqp6zNmRp/+IiIjsBUNVPcb7VBEREdkPhqp6jKf/iIiI7IddhKoFCxYgMDAQarUaYWFh2LVr123r165di3bt2kGtViM4OBgbNmywWC6EwPTp0+Hj4wMnJydERkbi9OnTFjXvvPMOevXqBWdnZ7i7u1e4nbS0NERHR8PZ2RleXl549dVXUVxsP6NCPP1HRERkP2weqlavXo1JkyZhxowZ2LdvH7p06YKoqChkZGRUWL9jxw7ExsZi9OjR2L9/P2JiYhATE4MjR45INbNnz8b8+fOxaNEipKSkwMXFBVFRUSgoKJBqjEYjBg8ejHHjxlW4HZPJhOjoaBiNRuzYsQPLli3D0qVLMX36dOsegLvAkSoiIiI7ImysR48eYvz48dJrk8kkfH19RUJCQoX1Q4YMEdHR0RZtYWFhYuzYsUIIIcxms9DpdGLOnDnS8uzsbKFSqcTKlSvLrW/JkiVCq9WWa9+wYYOQy+VCr9dLbQsXLhQajUYUFhZWad8MBoMAIAwGQ5Xqq2v5zvMi4F/rxbPLdtfK+omIiBqjmn5/23Skymg0Yu/evYiMjJTa5HI5IiMjkZycXOF7kpOTLeoBICoqSqpPTU2FXq+3qNFqtQgLC6t0nZVtJzg4GN7e3hbbycnJwdGjRyt8T2FhIXJyciwetclJWfLx8fQfERGR7dk0VGVmZsJkMlkEFwDw9vaGXq+v8D16vf629aXP1VlndbZTdhu3SkhIgFarlR7+/v5V3l5N8OafRERE9sPmc6oakilTpsBgMEiPCxcu1Or2nDmnioiIyG7YNFR5enpCoVAgPT3doj09PR06na7C9+h0utvWlz5XZ53V2U7ZbdxKpVJBo9FYPGqTE3/7j4iIyG7YNFQplUqEhIQgKSlJajObzUhKSkJ4eHiF7wkPD7eoB4DExESpPigoCDqdzqImJycHKSkpla6zsu0cPnzY4irExMREaDQadOjQocrrqU1Ojrz5JxERkb1wsHUHJk2ahLi4OISGhqJHjx6YN28e8vPzMWrUKADAiBEj4Ofnh4SEBADAxIkTERERgblz5yI6OhqrVq3Cnj17sHjxYgCATCZDfHw8Zs2ahdatWyMoKAjTpk2Dr68vYmJipO2mpaUhKysLaWlpMJlMOHDgAACgVatWcHV1Rb9+/dChQwc8/fTTmD17NvR6PaZOnYrx48dDpVLV6TGqDE//ERER2Q+bh6qhQ4fi8uXLmD59OvR6Pbp27YpNmzZJk8LT0tIgl98cUOvVqxdWrFiBqVOn4vXXX0fr1q2xbt06dOrUSaqZPHky8vPzMWbMGGRnZ+P+++/Hpk2boFarpZrp06dj2bJl0utu3boBALZs2YLevXtDoVBg/fr1GDduHMLDw+Hi4oK4uDi89dZbtX1IqsxZWfLxXTeaIISATCazcY+IiIgaL5kQQti6Ew1VTk4OtFotDAZDrcyvyikoQuc3fwEAnHi7P9Q3TgcSERFRzdX0+5tX/9VjLsqbA435hZxXRUREZEsMVfWYQi6TJqvnF3JeFRERkS0xVNVzLqqS0ao8jlQRERHZFENVPeequjFSxdsqEBER2RRDVT3HkSoiIiL7wFBVz5WGKk5UJyIisi2GqnrOlaGKiIjILjBU1XM3T//x6j8iIiJbYqiq56SJ6hypIiIisimGqnqu9AagDFVERES2xVBVz/HqPyIiIvvAUFXPcaI6ERGRfWCoquc4UZ2IiMg+MFTVcy6cqE5ERGQXGKrqOen0H3+mhoiIyKYYquo5ZyUnqhMREdkDhqp6zk19I1QVMFQRERHZEkNVPadROwIAchmqiIiIbIqhqp7TOJWMVF0vMsFYbLZxb4iIiBovhqp6rnSiOgDkFhTZsCdERESNG0NVPeegkEvBKoenAImIiGyGoaoB0NyYrJ5znSNVREREtsJQ1QBonEomq+fw9B8REZHNMFQ1AKVXAOZc5+k/IiIiW2GoagBKrwDkSBUREZHtMFQ1ADdHqhiqiIiIbIWhqgHgnCoiIiLbY6hqAG5e/cc5VURERLbCUNUAcKSKiIjI9hiqGgDOqSIiIrI9hqoG4ObVfzz9R0REZCsMVQ0AR6qIiIhsj6GqAeCcKiIiIttjqGoAeEd1IiIi22OoagC0N0aqrheZYCw227g3REREjRNDVQPgeuM+VQCQy1OARERENmEXoWrBggUIDAyEWq1GWFgYdu3addv6tWvXol27dlCr1QgODsaGDRsslgshMH36dPj4+MDJyQmRkZE4ffq0RU1WVhaGDx8OjUYDd3d3jB49Gnl5eRY1a9asQdeuXeHs7IyAgADMmTPHOjtsZQq5DG4qXgFIRERkSzYPVatXr8akSZMwY8YM7Nu3D126dEFUVBQyMjIqrN+xYwdiY2MxevRo7N+/HzExMYiJicGRI0ekmtmzZ2P+/PlYtGgRUlJS4OLigqioKBQUFEg1w4cPx9GjR5GYmIj169dj27ZtGDNmjLR848aNGD58OJ5//nkcOXIEn332GT766CN8+umntXcw7oI0WZ1XABIREdmGsLEePXqI8ePHS69NJpPw9fUVCQkJFdYPGTJEREdHW7SFhYWJsWPHCiGEMJvNQqfTiTlz5kjLs7OzhUqlEitXrhRCCHHs2DEBQOzevVuq2bhxo5DJZOLixYtCCCFiY2PFP/7xD4vtzJ8/XzRv3lyYzeYq7ZvBYBAAhMFgqFL93Yj6aKsI+Nd68dvJjFrfFhERUUNW0+9vm45UGY1G7N27F5GRkVKbXC5HZGQkkpOTK3xPcnKyRT0AREVFSfWpqanQ6/UWNVqtFmFhYVJNcnIy3N3dERoaKtVERkZCLpcjJSUFAFBYWAi1Wm2xHScnJ/z11184f/78Xex17fBwUQIAsq8ZbdwTIiKixsmmoSozMxMmkwne3t4W7d7e3tDr9RW+R6/X37a+9PlONV5eXhbLHRwc4OHhIdVERUXh22+/RVJSEsxmM06dOoW5c+cCAC5dulRh3woLC5GTk2PxqCtNboSqrHyGKiIiIluw+Zwqe/Xcc89hwoQJGDhwIJRKJXr27Ilhw4YBKBlNq0hCQgK0Wq308Pf3r7P+ejiXhKqrDFVEREQ2YdNQ5enpCYVCgfT0dIv29PR06HS6Ct+j0+luW1/6fKeaWyfCFxcXIysrS6qRyWR4//33kZeXh/Pnz0Ov16NHjx4AgJYtW1bYtylTpsBgMEiPCxcu3PEYWIs0UsXTf0RERDZh01ClVCoREhKCpKQkqc1sNiMpKQnh4eEVvic8PNyiHgASExOl+qCgIOh0OouanJwcpKSkSDXh4eHIzs7G3r17pZrNmzfDbDYjLCzMYt0KhQJ+fn5QKpVYuXIlwsPD0axZswr7plKpoNFoLB51xcO55Oq/q/m8+o+IiMgWHO5cUrsmTZqEuLg4hIaGokePHpg3bx7y8/MxatQoAMCIESPg5+eHhIQEAMDEiRMRERGBuXPnIjo6GqtWrcKePXuwePFiACUjTPHx8Zg1axZat26NoKAgTJs2Db6+voiJiQEAtG/fHv3798dzzz2HRYsWoaioCBMmTMCwYcPg6+sLoGS+19dff43evXujoKAAS5Yswdq1a7F169a6P0hVwDlVREREtmXzUDV06FBcvnwZ06dPh16vR9euXbFp0yZponlaWprFHKZevXphxYoVmDp1Kl5//XW0bt0a69atQ6dOnaSayZMnIz8/H2PGjEF2djbuv/9+bNq0yeJqvuXLl2PChAno27cv5HI5nnzyScyfP9+ib8uWLcMrr7wCIQTCw8Px22+/SacA7U3p1X9XefqPiIjIJmRCCGHrTjRUOTk50Gq1MBgMtX4q8MhFAwZ+8ge8NSqkvB555zcQERFRhWr6/c2r/xoIaaQqvwjMyURERHWPoaqBaHLjlgpGkxn5RpONe0NERNT4MFQ1EE5KBdSOJR8n71VFRERU9xiqGpDSG4DyCkAiIqK6x1DVgPAGoERERLbDUNWA3JyszlBFRERU1xiqGpAmPP1HRERkMwxVDQhvAEpERGQ7DFUNCEeqiIiIbIehqgFp6loSqjLzGKqIiIjqGkNVA+LlpgIAXM4ttHFPiIiIGh+GqgakGUMVERGRzTBUNSBlQxV//4+IiKhuMVQ1IJ6uJaHKaDIj53qxjXtDRETUuDhUtTAnJ6fKK9VoNDXqDN0dtaMCWidHGK4X4XJeAbTOjrbuEhERUaNR5VDl7u4OmUxWpVqTyVTjDtHdaeamguF6ETJyC9HKy83W3SEiImo0qhyqtmzZIv197tw5vPbaaxg5ciTCw8MBAMnJyVi2bBkSEhKs30uqsmauKvyZkcfJ6kRERHWsyqEqIiJC+vutt97Chx9+iNjYWKlt0KBBCA4OxuLFixEXF2fdXlKV8QpAIiIi26jRRPXk5GSEhoaWaw8NDcWuXbvuulNUc7xXFRERkW3UKFT5+/vj888/L9f+xRdfwN/f/647RTXHkSoiIiLbqPLpv7I++ugjPPnkk9i4cSPCwsIAALt27cLp06fxzTffWLWDVD2loSqDoYqIiKhO1WikasCAATh9+jQGDRqErKwsZGVl4dFHH8WpU6cwYMAAa/eRqsHLTQ2AI1VERER1rdojVUVFRejfvz8WLVqEd955pzb6RHdBOv2Xx1BFRERUl6o9UuXo6IhDhw7VRl/ICkonqmflG1FYzPuFERER1ZUanf576qmn8OWXX1q7L2QF7s6OUDmUfKzpBo5WERER1ZUaTVQvLi7GV199hV9//RUhISFwcXGxWP7hhx9apXNUfTKZDL7uTkjNzMffhuto0dTZ1l0iIiJqFGoUqo4cOYJ7770XAHDq1CmLZVX9KRuqPTqNGqmZ+bhkuG7rrhARETUaNQpVZX+yhuyPj3vJFYCXDAU27gkREVHjUaM5VWTffLVOAIBL2QxVREREdaVGI1UAsGfPHqxZswZpaWkwGo0Wy7799tu77hjV3M2RKp7+IyIiqis1GqlatWoVevXqhePHj+O7775DUVERjh49is2bN0Or1Vq7j1RNPtqSUPU3R6qIiIjqTI1C1bvvvouPPvoIP/74I5RKJT7++GOcOHECQ4YMQYsWLazdR6omn9LTfxypIiIiqjM1ClVnzpxBdHQ0AECpVCI/Px8ymQwvvfQSFi9ebNUOUvWVzqm6eq0IBUW8ASgREVFdqFGoatKkCXJzcwEAfn5+OHLkCAAgOzsb165ds17vqEY0Tg5wclQA4BWAREREdaVGoerBBx9EYmIiAGDw4MGYOHEinnvuOcTGxqJv375W7SBVn0wmuzlZPZunAImIiOpCja7++/TTT1FQUDIC8sYbb8DR0RE7duzAk08+ialTp1q1g1QzvlonnL2cj4sMVURERHWiRqHKw8ND+lsul+O1116zWofIOvw9SuZVXbjKUEVERFQXanT6r0+fPpg5c2a59qtXr6JPnz7VXt+CBQsQGBgItVqNsLAw7Nq167b1a9euRbt27aBWqxEcHIwNGzZYLBdCYPr06fDx8YGTkxMiIyNx+vRpi5qsrCwMHz4cGo0G7u7uGD16NPLy8ixqfv75Z/Ts2RNubm5o1qwZnnzySZw7d67a+2cL/h4lv/l3IYtz3IiIiOpCjULVb7/9hk8//RQxMTHIz8+X2o1GI7Zu3Vqtda1evRqTJk3CjBkzsG/fPnTp0gVRUVHIyMiosH7Hjh2IjY3F6NGjsX//fsTExCAmJkaaLA8As2fPxvz587Fo0SKkpKTAxcUFUVFR0ilLABg+fDiOHj2KxMRErF+/Htu2bcOYMWOk5ampqXjsscfQp08fHDhwAD///DMyMzPxxBNPVGv/bMW/CUMVERFRnRI1IJPJxIEDB0RYWJjo1KmTSE1NFUIIodfrhVwur9a6evToIcaPHy+9NplMwtfXVyQkJFRYP2TIEBEdHW3RFhYWJsaOHSuEEMJsNgudTifmzJkjLc/OzhYqlUqsXLlSCCHEsWPHBACxe/duqWbjxo1CJpOJixcvCiGEWLt2rXBwcBAmk0mq+eGHH4RMJhNGo7FK+2YwGAQAYTAYqlRvTQfSroqAf60X3Wcl1vm2iYiI6rOafn/X+Lf/fHx8sHXrVgQHB6N79+747bffqr0Oo9GIvXv3IjIyUmqTy+WIjIxEcnJyhe9JTk62qAeAqKgoqT41NRV6vd6iRqvVIiwsTKpJTk6Gu7s7QkNDpZrIyEjI5XKkpKQAAEJCQiCXy7FkyRKYTCYYDAb897//RWRkJBwdHSvsW2FhIXJyciwetlJ6+i8jt5D3qiIiIqoDNQpVMpkMAKBSqbBixQpMnDgR/fv3x2effVat9WRmZsJkMsHb29ui3dvbG3q9vsL36PX629aXPt+pxsvLy2K5g4MDPDw8pJqgoCD88ssveP3116FSqeDu7o6//voLa9asqXR/EhISoNVqpYe/v/+dDkGtaeLsCFdVyXUIf13lKUAiIqLaVqNQJYSweD116lQsX74cc+fOtUqn7IFer8dzzz2HuLg47N69G1u3boVSqcQ//vGPcvtfasqUKTAYDNLjwoULddzrm2QyWZnJ6rwCkIiIqLbV6JYKqampaNasmUXbk08+ibZt22Lv3r1VXo+npycUCgXS09Mt2tPT06HT6Sp8j06nu2196XN6ejp8fHwsarp27SrV3DoRvri4GFlZWdL7FyxYAK1Wi9mzZ0s1//vf/+Dv74+UlBT07NmzXN9UKhVUKlVVdr1O+DdxwvFLOUjjZHUiIqJaV6ORqoCAAOkUYFmdOnVCXFxcldejVCoREhKCpKQkqc1sNiMpKQnh4eEVvic8PNyiHgASExOl+qCgIOh0OouanJwcpKSkSDXh4eHIzs62CICbN2+G2WxGWFgYAODatWuQyy0Pj0KhkPpYH7TgbRWIiIjqTI1GqgBgz549WLNmDdLS0mA0Gi2Wffvtt1Vez6RJkxAXF4fQ0FD06NED8+bNQ35+PkaNGgUAGDFiBPz8/JCQkAAAmDhxIiIiIjB37lxER0dj1apV2LNnj/RDzjKZDPHx8Zg1axZat26NoKAgTJs2Db6+voiJiQEAtG/fHv3798dzzz2HRYsWoaioCBMmTMCwYcPg6+sLAIiOjsZHH32Et956C7GxscjNzcXrr7+OgIAAdOvWraaHrU6Vnv47z1BFRERU+2pyqeHKlSuFo6OjGDhwoFAqlWLgwIGiTZs2QqvVipEjR1Z7fZ988olo0aKFUCqVokePHmLnzp3SsoiICBEXF2dRv2bNGtGmTRuhVCpFx44dxU8//WSx3Gw2i2nTpglvb2+hUqlE3759xcmTJy1qrly5ImJjY4Wrq6vQaDRi1KhRIjc3t9x+duvWTbi4uIhmzZqJQYMGiePHj1d5v2x5SwUhhNhyIl0E/Gu9ePjD32yyfSIiovqopt/fMiEqmXV9G507d8bYsWMxfvx4uLm54eDBgwgKCsLYsWPh4+NT4d3WG6OcnBxotVoYDAZoNJo63/6FrGt4YPYWKB3kOP5Wfyjk5U/ZEhERkaWafn/XaE7VmTNnEB0dDaBkXlR+fj5kMhleeukl6TQc2Z6vuxOUDnIYi824yN8AJCIiqlU1ClVNmjRBbm4uAMDPz0/6iZjs7Gxcu8b5O/ZCIZchsGnJvKqzmXl3qCYiIqK7UaNQ9eCDDyIxMREAMHjwYEycOBHPPfccYmNj0bdvX6t2kO5OS09XAMDZy/l3qCQiIqK7UaOr/z799FPpx4nfeOMNODo6YseOHXjyyScxdepUq3aQ7k5QMxcAHKkiIiKqbdUKVaW/Zefg4ABXV1fp9QsvvIAXXnjB+r2ju9bS80ao4kgVERFRrapWqHJ3d6/wpp+3Mpn4A772omWzktN/qZkMVURERLWpWqFqy5Yt0t9CCAwYMABffPEF/Pz8rN4xso7SkapLhgLkFxbDRVXj+70SERHRbVTrGzYiIsLitUKhQM+ePdGyZUurdoqsp4mLEk1dlLiSb8SfGXno4u9u6y4RERE1SDW6+o/ql7Y6NwDASX2ujXtCRETUcDFUNQKloeoEQxUREVGtuetQVZWJ62Rb7W6EqlPpDFVERES1pVpzqp544gmL1wUFBXj++efh4uJi0f7tt9/efc/IatrqSn63iCNVREREtadaoUqr1Vq8fuqpp6zaGaodrb1KbquQmVeIK3mFaOqqsnGPiIiIGp5qhaolS5bUVj+oFrmoHNDCwxlpWddwUp+LXq0YqoiIiKyNE9UbCekKQM6rIiIiqhUMVY1EO95WgYiIqFYxVDUSvK0CERFR7WKoaiTKjlSZzMLGvSEiImp4GKoaiSBPV7goFbheZMKZy3m27g4REVGDw1DVSCjkMnT0K7klxsEL2bbtDBERUQPEUNWIdL4Rqg5fNNi4J0RERA0PQ1Uj0tnfHQBw6C+GKiIiImtjqGpESkeqjl3KgbHYbOPeEBERNSwMVY1IQFNnaNQOMBab+ePKREREVsZQ1YjIZDJ0bu4OgKcAiYiIrI2hqpEJbl46WT3bth0hIiJqYBiqGpkuN0aq9p3Ptmk/iIiIGhqGqkYmJKAJAOBURi4M14ps3BsiIqKGg6GqkWnmpkKQpwuEAPalXbV1d4iIiBoMhqpGKPTGaNXuc1k27gkREVHDwVDVCHUP9ADAUEVERGRNDFWNUGhgyUjVwQsGFBSZbNwbIiKihoGhqhEK8nSBp6sSRpMZR/g7gERERFbBUNUIyWQyhAaUnALcxVOAREREVsFQ1Uj1CCoJVclnrti4J0RERA0DQ1UjdX9rTwDArtQszqsiIiKyAoaqRqq1lyu83FQoLDZj33ner4qIiOhu2UWoWrBgAQIDA6FWqxEWFoZdu3bdtn7t2rVo164d1Go1goODsWHDBovlQghMnz4dPj4+cHJyQmRkJE6fPm1Rk5WVheHDh0Oj0cDd3R2jR49GXl6etPzNN9+ETCYr93BxcbHejtuQTCbD/a1KRqt+/zPTxr0hIiKq/2weqlavXo1JkyZhxowZ2LdvH7p06YKoqChkZGRUWL9jxw7ExsZi9OjR2L9/P2JiYhATE4MjR45INbNnz8b8+fOxaNEipKSkwMXFBVFRUSgoKJBqhg8fjqNHjyIxMRHr16/Htm3bMGbMGGn5K6+8gkuXLlk8OnTogMGDB9fewahj990IVdsZqoiIiO6esLEePXqI8ePHS69NJpPw9fUVCQkJFdYPGTJEREdHW7SFhYWJsWPHCiGEMJvNQqfTiTlz5kjLs7OzhUqlEitXrhRCCHHs2DEBQOzevVuq2bhxo5DJZOLixYsVbvfAgQMCgNi2bVuV981gMAgAwmAwVPk9dUlvuC4C/rVeBL62XlzNL7R1d4iIiOxCTb+/bTpSZTQasXfvXkRGRkptcrkckZGRSE5OrvA9ycnJFvUAEBUVJdWnpqZCr9db1Gi1WoSFhUk1ycnJcHd3R2hoqFQTGRkJuVyOlJSUCrf7xRdfoE2bNnjggQcq3Z/CwkLk5ORYPOyZt0aN1l6uEALY/ievAiQiIrobNg1VmZmZMJlM8Pb2tmj39vaGXq+v8D16vf629aXPd6rx8vKyWO7g4AAPD48Kt1tQUIDly5dj9OjRt92fhIQEaLVa6eHv73/bensQ0aYZACDpRLqNe0JERFS/2XxOVX3w3XffITc3F3FxcbetmzJlCgwGg/S4cOFCHfWw5vq2Lwmfv528DJNZ2Lg3RERE9ZdNQ5WnpycUCgXS0y1HSdLT06HT6Sp8j06nu2196fOdam6dCF9cXIysrKwKt/vFF19g4MCB5Ua/bqVSqaDRaCwe9i40sAm0To7IyjdifxpvrUBERFRTNg1VSqUSISEhSEpKktrMZjOSkpIQHh5e4XvCw8Mt6gEgMTFRqg8KCoJOp7OoycnJQUpKilQTHh6O7Oxs7N27V6rZvHkzzGYzwsLCLNadmpqKLVu23PHUX33lqJCjd9uSU4CJx3kKkIiIqKZsfvpv0qRJ+Pzzz7Fs2TIcP34c48aNQ35+PkaNGgUAGDFiBKZMmSLVT5w4EZs2bcLcuXNx4sQJvPnmm9izZw8mTJgAoOT+S/Hx8Zg1axZ++OEHHD58GCNGjICvry9iYmIAAO3bt0f//v3x3HPPYdeuXdi+fTsmTJiAYcOGwdfX16J/X331FXx8fPDII4/UzQGxgdJTgEnHK76NBREREd2Zg607MHToUFy+fBnTp0+HXq9H165dsWnTJulUW1paGuTym9mvV69eWLFiBaZOnYrXX38drVu3xrp169CpUyepZvLkycjPz8eYMWOQnZ2N+++/H5s2bYJarZZqli9fjgkTJqBv376Qy+V48sknMX/+fIu+mc1mLF26FCNHjoRCoajlI2E7EW2awUEuw58ZeTiXmY9Az4Zxg1MiIqK6JBNCcHZyLcnJyYFWq4XBYLD7+VVPf5mC309nYnL/tnihdytbd4eIiMhmavr9bfPTf2QfooN9AADrD16ycU+IiIjqJ4YqAgBEddRBIZfh2KUcnL2cd+c3EBERkQWGKgIANHFRSr8FuOEwR6uIiIiqi6GKJANLTwEeYqgiIiKqLoYqkvTr6A1HhQwn9Lk4fsm+f7eQiIjI3jBUkcTdWYm+7UpuZbF2z1827g0REVH9wlBFFgaHNgcArDtwEcZis417Q0REVH8wVJGFiDbN0MxNhax8I7ac5B3WiYiIqoqhiiw4KOR4opsfAJ4CJCIiqg6GKiqn9BTglpMZuJxbaOPeEBER1Q8MVVROKy83dPV3h8kssGbPBVt3h4iIqF5gqKIKPd0zAADwv53nUWzihHUiIqI7YaiiCg3s4oOmLkpcMhTgl2Pptu4OERGR3WOoogqpHBSI7dECALB0xznbdoaIiKgeYKiiSj3VMwAKuQy7UrN4h3UiIqI7YKiiSum0avTvpAMAfPlHqo17Q0REZN8Yqui2nr0/CACwbv9FXMy+buPeEBER2S+GKrqtbi2aoNc9TVFsFvh821lbd4eIiMhuMVTRHY1/qBUAYOWuNGTm8WagREREFWGoojvqdU9TdPF3R2GxGV9xbhUREVGFGKrojmQyGcb3vgcAsGzHOVzhaBUREVE5DFVUJZHtvdHJT4N8owmf/XbG1t0hIiKyOwxVVCVyuQyvRrUDAPx353leCUhERHQLhiqqsgdbeyIsyAPGYjM+/vWUrbtDRERkVxiqqMpkMhkm9y8Zrfp67184qc+1cY+IiIjsB0MVVUtIQBP076iDWQBv/nAUQghbd4mIiMguMFRRtb0R3R4qBzmSz17BhsN6W3eHiIjILjBUUbX5ezjj+YiSWyy889MxXDeabNwjIiIi22OoohoZ1/se+Lk74W9DARb+9qetu0NERGRzDFVUI2pHBaYNbA8AWLT1LE6lc9I6ERE1bgxVVGNRHXWIbO8Fo8mMV78+hGKT2dZdIiIishmGKqoxmUyGWTHBcFM74OCFbHy1nb8LSEREjRdDFd0VnVaNqdElpwHn/nIKZy/n2bhHREREtsFQRXdtSKg/7m/licJiM15acxBFPA1IRESNEEMV3TWZTIb3/9EZmhunAT9M5E/YEBFR48NQRVbh5+6E957sDABYtPUM/jidaeMeERER1S27CFULFixAYGAg1Go1wsLCsGvXrtvWr127Fu3atYNarUZwcDA2bNhgsVwIgenTp8PHxwdOTk6IjIzE6dOnLWqysrIwfPhwaDQauLu7Y/To0cjLyyu3ng8++ABt2rSBSqWCn58f3nnnHevsdAM0INgHsT1aQAjgpTUHkJlXaOsuERER1Rmbh6rVq1dj0qRJmDFjBvbt24cuXbogKioKGRkZFdbv2LEDsbGxGD16NPbv34+YmBjExMTgyJEjUs3s2bMxf/58LFq0CCkpKXBxcUFUVBQKCgqkmuHDh+Po0aNITEzE+vXrsW3bNowZM8ZiWxMnTsQXX3yBDz74ACdOnMAPP/yAHj161M6BaCCmD+yA1l6uuJxbiBeW7+P8KiIiajyEjfXo0UOMHz9eem0ymYSvr69ISEiosH7IkCEiOjraoi0sLEyMHTtWCCGE2WwWOp1OzJkzR1qenZ0tVCqVWLlypRBCiGPHjgkAYvfu3VLNxo0bhUwmExcvXpRqHBwcxIkTJ2q8bwaDQQAQBoOhxuuoj06n54iO0zeJgH+tFzO+P2Lr7hAREVVLTb+/bTpSZTQasXfvXkRGRkptcrkckZGRSE5OrvA9ycnJFvUAEBUVJdWnpqZCr9db1Gi1WoSFhUk1ycnJcHd3R2hoqFQTGRkJuVyOlJQUAMCPP/6Ili1bYv369QgKCkJgYCCeffZZZGVlVbo/hYWFyMnJsXg0Rq283PDhkC4AgKU7zmHtngs27hEREVHts2moyszMhMlkgre3t0W7t7c39Hp9he/R6/W3rS99vlONl5eXxXIHBwd4eHhINWfPnsX58+exdu1a/Oc//8HSpUuxd+9e/OMf/6h0fxISEqDVaqWHv7//nQ5Bg9Wvow7/7NsaAPDGuiPYlVp5GCUiImoIbD6nyl6ZzWYUFhbiP//5Dx544AH07t0bX375JbZs2YKTJ09W+J4pU6bAYDBIjwsXGvcITXzf1ujXwRvGYjOe+88e/JnB3wckIqKGy6ahytPTEwqFAunp6Rbt6enp0Ol0Fb5Hp9Pdtr70+U41t06ELy4uRlZWllTj4+MDBwcHtGnTRqpp377kzuFpaWkV9k2lUkGj0Vg8GjO5XIaPh3VDtxbuMFwvQtxXu5GRU3DnNxIREdVDNg1VSqUSISEhSEpKktrMZjOSkpIQHh5e4XvCw8Mt6gEgMTFRqg8KCoJOp7OoycnJQUpKilQTHh6O7Oxs7N27V6rZvHkzzGYzwsLCAAD33XcfiouLcebMGanm1KmSm1oGBATczW43Kk5KBb6M644gTxdczL6OkUt2I7egyNbdIiIisr5amjhfZatWrRIqlUosXbpUHDt2TIwZM0a4u7sLvV4vhBDi6aefFq+99ppUv337duHg4CA++OADcfz4cTFjxgzh6OgoDh8+LNW89957wt3dXXz//ffi0KFD4rHHHhNBQUHi+vXrUk3//v1Ft27dREpKivjjjz9E69atRWxsrLTcZDKJe++9Vzz44INi3759Ys+ePSIsLEw8/PDDVd63xnr1X0XOZ+aLkLd/EQH/Wi+e+Gy7yCsosnWXiIiIKlTT72+bhyohhPjkk09EixYthFKpFD169BA7d+6UlkVERIi4uDiL+jVr1og2bdoIpVIpOnbsKH766SeL5WazWUybNk14e3sLlUol+vbtK06ePGlRc+XKFREbGytcXV2FRqMRo0aNErm5uRY1Fy9eFE888YRwdXUV3t7eYuTIkeLKlStV3i+GKkuH/8oWwTNKbrUweNEOkV/IYEVERPanpt/fMiGEsO1YWcOVk5MDrVYLg8HQ6OdXlTp4IRtPfZGC3MJi3NeqKb6M6w61o8LW3SIiIpLU9PubV/9Rneri746lz/SAi1KB7X9eQdxXuzjHioiIGgSGKqpzIQFNsPSZHnBTOSAlNQv/93kKrvB3AomIqJ5jqCKb6B7ogZVjesLDRYnDFw0Y8u9k/J193dbdIiIiqjGGKrKZTn5arBkbDl+tGmcu5+Pxz7bj8F8GW3eLiIioRhiqyKZaebli7bheaOPtivScQgz5dzI2Han4J4qIiIjsGUMV2ZyfuxO+HtcLD7T2xPUiE8Yt34tFW8+AF6YSEVF9wlBFdkGjdsSSkd3xdM8ACAG8t/EE/rnqAPILi23dNSIioiphqCK74aCQ463HOuLNRzvAQS7Djwf/xqBP/8DpdP4QMxER2T+GKrIrMpkMI+8LwqoxPeGtUeHM5Xw8tmA7vj9w0dZdIyIiui2GKrJLoYEe+OmfD6DXPU1xzWjCxFUHMHHVfhiu80ahRERknxiqyG55uqrw39FhmNi3NRRyGb4/8DcembcNO85k2rprRERE5TBUkV1TyGV46eE2WPt8OAKaOuNvQwGGf5GCt9cfw3WjydbdIyIikjBUUb1wb4sm2PDPBxDbowWEAL78IxX95m3FtlOXbd01IiIiAAxVVI+4qByQ8EQwlozsDl+tGheyrmPEV7vw0uoD/O1AIiKyOYYqqnceaueFXyZFYGSvQMhkwHf7L6Lvh1vx3+RzKDaZbd09IiJqpGSCt62uNTk5OdBqtTAYDNBoNLbuToN04EI2XvvmEE7oS+5l1dbbDdMf7YD7WnnauGdERFRf1fT7m6GqFjFU1Y1ikxkrd6VhbuIpZF8rueXCwx288fqA9gjydLFx74iIqL5hqLJDDFV1K/uaEfN+PY3/7jwPk1lAIZdhcEhz/LNva/i6O9m6e0REVE8wVNkhhirbOJ2ei3c3HMeWkyVXBioVcjzVMwAvPHQPPF1VNu4dERHZO4YqO8RQZVt7zmVhzs8nkZKaBQBwVirwdHgARt8fBC83tY17R0RE9oqhyg4xVNmeEAJ//JmJOT+fxKG/DAAApYMcg0OaY+yD96BFU2cb95CIiOwNQ5UdYqiyH0IIJB3PwGe//Yl9adkASu7WPrCzD8Y82BIdfbW27SAREdkNhio7xFBlf4QQSEnNwme/nbG4G3v3wCYY2SsI/Tp6w1HB27cRETVmDFV2iKHKvh25aMDibWex4fAlFJtL/jPQadR4qmcLxPZogaac1E5E1CgxVNkhhqr6IT2nAMt3nseKXWnIzDMCKLli8OGO3hga6o/7W3lCLpfZuJdERFRXGKrsEENV/VJYbMJPhy5h2Y5zOHhjUjsA+Lk74R8hzTE4tDmaN+HEdiKiho6hyg4xVNVfRy4asGbPBazbfxE5BcUAAJkMuO8eTzzW1RdRnXTQqB1t3EsiIqoNDFV2iKGq/isoMuHno3qs3n0BO85ckdqVDnI81LYZBnXxQ9/2XlA7KmzYSyIisiaGKjvEUNWwXMi6hu8PXMT3B/7G6Yw8qd1V5YB+HbzRv5MOD7ZpxoBFRFTPMVTZIYaqhkkIgRP6XPxw8G/8cOBvXMy+Li1zclQgok0z9OvojT7tvODurLRhT4mIqCYYquwQQ1XDJ4TAvrSrWH/oEn45mm4RsBRyGXq29EC/Djo81NaLd28nIqonGKrsEENV4yKEwNG/c/DLUT1+OZaOE/pci+VBni6IaNMMEW2boWdQUzgpeZqQiMgeMVTZIYaqxu1cZj4Sj6Xj1+Pp2Hv+qnSDUaBkontYkAci2jTD/a090cbLjffCIiKyEwxVdoihikrlFhRh+59XsPXUZWw9mYG/DQUWyz1clOjZ0gM9WzZFeMumaOXlCpmMIYuIyBYYquwQQxVVRAiBPzPySgLWqcvYc+4qrheZLGo8XVXo2dID4fc0RViQB1p6unIki4iojjBU2SGGKqoKY7EZB//Kxs4zV5B89gr2nr+KwmKzRY27syPubdEEIQFNcG+LJujir4Wz0sFGPSYiatgYquwQQxXVREGRCQcuZCP5zBXsPHsFBy5klwtZCrkMHXw0CAlogm4t3NHV3x0tPJx5ypCIyApq+v0tr8U+VdmCBQsQGBgItVqNsLAw7Nq167b1a9euRbt27aBWqxEcHIwNGzZYLBdCYPr06fDx8YGTkxMiIyNx+vRpi5qsrCwMHz4cGo0G7u7uGD16NPLybt7Q8dy5c5DJZOUeO3futN6OE1VA7ahAz5ZN8dLDbbB6bDgOvxmF78ffh+kDOyC6sw98tGqYzAKHLxqwdMc5TFx1ABFzfkOXmb9g+Bc7kbDxOH46dAkXsq6B/5+JiKju2HykavXq1RgxYgQWLVqEsLAwzJs3D2vXrsXJkyfh5eVVrn7Hjh148MEHkZCQgIEDB2LFihV4//33sW/fPnTq1AkA8P777yMhIQHLli1DUFAQpk2bhsOHD+PYsWNQq9UAgEceeQSXLl3Cv//9bxQVFWHUqFHo3r07VqxYAaAkVAUFBeHXX39Fx44dpe03bdoUjo5V+803jlRRbfk7+zr2pV3F3vNXsS8tG8cv5cB4y2gWUHLaMNhPi05+WnTy1aK9jxsCmrpAwflZRESVqren/8LCwtC9e3d8+umnAACz2Qx/f3+8+OKLeO2118rVDx06FPn5+Vi/fr3U1rNnT3Tt2hWLFi2CEAK+vr54+eWX8corrwAADAYDvL29sXTpUgwbNgzHjx9Hhw4dsHv3boSGhgIANm3ahAEDBuCvv/6Cr6+vFKr279+Prl271mjfGKqorhSZzDiVnovDfxlw6KIBRy4acPxSDopM5f/zVjvK0dbbDe10GrTzufGsc0MTF979nYgIqPn3t01nuhqNRuzduxdTpkyR2uRyOSIjI5GcnFzhe5KTkzFp0iSLtqioKKxbtw4AkJqaCr1ej8jISGm5VqtFWFgYkpOTMWzYMCQnJ8Pd3V0KVAAQGRkJuVyOlJQUPP7441L7oEGDUFBQgDZt2mDy5MkYNGhQpftTWFiIwsJC6XVOTk7VDgTRXXJUyNHRV4uOvloMu9FWWGzCKX0eDl804PDFbBz7Owcn03NRUGTGwb8MOPiXwWIdOo0a7Xzc0FbnhtZebmjl5Yp7mrnATV21kVkiosbOpqEqMzMTJpMJ3t7eFu3e3t44ceJEhe/R6/UV1uv1eml5advtam49tejg4AAPDw+pxtXVFXPnzsV9990HuVyOb775BjExMVi3bl2lwSohIQEzZ86syq4T1TqVgwLBzbUIbq4F0AIAYDILnL+SjxP6XJy4lIPj+lyc0OfgQtZ16HMKoM8pwG8nL1usx1ujuhGwXC2evdxUnBhPRFQGr8muhKenp8WIWPfu3fH3339jzpw5lYaqKVOmWLwnJycH/v7+td5XoqpSyGVo2cwVLZu5YkCwj9SeW1CEU+m5OH4pFyf1ufgzIw9nLuchI7cQ6Tklj+1/XrFYl5vKAS29XHGPpwsCmrog0NO55LmpM39ImogaJZuGKk9PTygUCqSnp1u0p6enQ6fTVfgenU532/rS5/T0dPj4+FjUlM6N0ul0yMjIsFhHcXExsrKyKt0uUDL/KzExsdLlKpUKKpWq0uVE9spN7YiQAA+EBHhYtBuuF+HM5TycycjDn5fzcCYjH2cu5+H8lXzkFhbj4IVsHLyQXW59WidHBDZ1RosbISugzLOnq5IjXETUINk0VCmVSoSEhCApKQkxMTEASiaqJyUlYcKECRW+Jzw8HElJSYiPj5faEhMTER4eDgAICgqCTqdDUlKSFKJycnKQkpKCcePGSevIzs7G3r17ERISAgDYvHkzzGYzwsLCKu3vgQMHLIIaUUOndSq56ei9LZpYtBcWm3D+yjX8mZGHc1fycT7zWsnzlWvQ5xTAcL2ownlbAOCsVKB5Eyf4uTuheRNn+DVxkl77NXFCM1eeViSi+snmp/8mTZqEuLg4hIaGokePHpg3bx7y8/MxatQoAMCIESPg5+eHhIQEAMDEiRMRERGBuXPnIjo6GqtWrcKePXuwePFiAIBMJkN8fDxmzZqF1q1bS7dU8PX1lYJb+/bt0b9/fzz33HNYtGgRioqKMGHCBAwbNgy+vr4AgGXLlkGpVKJbt24AgG+//RZfffUVvvjiizo+QkT2R+WgQBtvN7Txdiu37LrRhLSskpCVduVm2Dp3JR9/Z1/HNaMJp9LzcCo9r4I1AyoHuRSwmje5EbzcneDr7gQfrRpeGhVUDora3kUiomqzeagaOnQoLl++jOnTp0Ov16Nr167YtGmTNNE8LS0NcvnNe5T26tULK1aswNSpU/H666+jdevWWLdunXSPKgCYPHky8vPzMWbMGGRnZ+P+++/Hpk2bpHtUAcDy5csxYcIE9O3bF3K5HE8++STmz59v0be3334b58+fh4ODA9q1a4fVq1fjH//4Ry0fEaL6zUmpQFtdyVWEtyosNuHi1eu4mH0dF69ex183/v7r6jX8dbVksnxhsRlnM/NxNjO/0m00dVFCp1XDR6uGt6bssxN0WjV0WjVcVTb/nzciamRsfp+qhoz3qSKqHmOxGXpDAf7KLglZpcHrr6slpxUvGQoqvMlpRdxUDlLAauamKnm4qqS/vdxK2jVqB55uJCIL9fI+VUREZSkd5GjR1BktmjpXuFwIgexrRbhkKIA+5zr0hkLoDdelwJV+4zm3oBi5hcXIzcjD6YyKTzOW3WbZsHVr+Cp93cRFCRelggGMiCrFUEVE9YZMJkMTFyWauCjRwbfy//eYX1hcct8tQ8njcl4hLueWPDJyC6S/cwqKYSw2l5yOzL5+x+0rHeRo6qKEx41Hyd8qeLg43nhWoqnrzWUatSPk/EkgokaDoYqIGhwXlQPuaVZyo9LbKSgyIbNM4LIMXzf/vpJfiIIiM4zFZlwylIyGVYVCLkMTZ0cphHm4KOHurIS7kyPcnR3h7qSE1tnxxmsl3J0doXVyhNqRE/GJ6iOGKiJqtNSOCjRv4ozmTSo+3VjWNWMxruQZkZVf8riSb0RWfiGy8otuPJe2GZGVZ0RuYTFMZoHMPCMy84zV7Jcc7k43Q1ZpAHN3drwRwm4uc1M7QKMueXZTO0LpIL/zBoioVjBUERFVgbPSAc4eDvD3uHMAA0qudLyaX1QmhBXiar4RhuvFyL5uhOFaEbKvFyH7mhHZ14uk1yazQEGRGfqikp8Nqi61oxxuakdoboQsjRS8boav0jY3VZnlN55dlQ48ZUlUQwxVRES1QOWggE6rgE6rvnPxDUII5BUWI/taEQzXi5B9rQjZ141lXhtvtJWGMGPJpPyCYuQVFgMACorMKCgqOW1ZEzIZ4KpygKvKAS43Hq4qBVyU5dtcpb/LtjvApcwyRwVHzqjxYKgiIrITMpkMbmpHuKkdUd1fDTWZBfIKipFTUIScgiLkFhQj5/qN5xuvcwuKkHO9GLmFN54Lbi4vnbQvBKSgZg1KB7kUtMoGM1eVA5yUCjgrFSXPjg43/5bab7Q5lrbdfA/DGtkjhioiogZAIZdBe2POVU0VFJmk8JVXWDL6lV9oQr70d/GNv2+0GS3b8gqLkF9oQl5hsXQ/MWOxGVnFRmRVfi/XGnFUyG6ELcsw5qR0gLOjolybk6MCakc51I4K6W+VowJqh5K/nZSlf9+sUznIeQsNqhaGKiIiAoAbgUKBZm53/8PwRSZzmTBmuiWUlTxfKzLhutGEazce143FJc9FFbQZTbhWZILJLG6sX6DIVIwcK42oVaY0YJWGr9JjdGu7k1IB1S2hzOmWgKZ0kEPloLjxfPP1zb9LnpUKhrn6iqGKiIiszlEhv3GbCKXV1imEgNFkviWImXDNaBnQSoPYzYBWjOtGMwqKTSgsMt2Yd1ayrODG68LikufrZYIbUDpHzQygyGr7URWlIUtVSfAqH84qCmnla0r/dlTcfCgVcjg6yKS/by6/2caLF6qGoYqIiOoFmUx2IzQo4F61izBrpMhklsJWQZEJhcUmKZQV3BLKyoa0gjLBrKDIhMIy7YVFZhhN5jLPJul1YXFJW1nG4pL7ouXW3m5Wi0IuswhZjlL4kpX5W16uxvFGjapckJOVWV7m9Y02pUIGB7kcDgoZlAo5HBQlfzvKSwKgg/zmtpq5qexmjh1DFRERURmlX+5uVb9w866ZzSWjcJUFr5sBzARj8Y0gVlzyutDitWV76d+lywqLzSg2mWE0CRSZSpYXmcxl/i5pLzZb/iywySyk233Ym18nPYhWXuV/wN0WGKqIiIhsTC6XQS0vmZOFOgxzlTGbBYrMN0LWjeBVKAWwG4HMZL6xrMzrMgHNWOa9RWWCXGlbhcHOJGAsNqHYJFBkFig2mUv+NplRZC7zt6lkWZFJ2M0oFcBQRURERLeQy2VQyRVQOQC4++sWGg37iXdERERE9RhDFREREZEVMFQRERERWQFDFREREZEVMFQRERERWQFDFREREZEVMFQRERERWQFDFREREZEVMFQRERERWQFDFREREZEVMFQRERERWQFDFREREZEVMFQRERERWQFDFREREZEVONi6Aw2ZEAIAkJOTY+OeEBERUVWVfm+Xfo9XFUNVLcrNzQUA+Pv727gnREREVF25ubnQarVVrpeJ6sYwqjKz2Yy///4bbm5ukMlkNV5PTk4O/P39ceHCBWg0Giv2kG7FY113eKzrDo913eGxrlu1dbyFEMjNzYWvry/k8qrPlOJIVS2Sy+Vo3ry51dan0Wj4H2kd4bGuOzzWdYfHuu7wWNet2jje1RmhKsWJ6kRERERWwFBFREREZAUMVfWASqXCjBkzoFKpbN2VBo/Huu7wWNcdHuu6w2Ndt+zteHOiOhEREZEVcKSKiIiIyAoYqoiIiIisgKGKiIiIyAoYqoiIiIisgKHKzi1YsACBgYFQq9UICwvDrl27bN0lu5KQkIDu3bvDzc0NXl5eiImJwcmTJy1qCgoKMH78eDRt2hSurq548sknkZ6eblGTlpaG6OhoODs7w8vLC6+++iqKi4stan777Tfce++9UKlUaNWqFZYuXVquP43p83rvvfcgk8kQHx8vtfFYW8/Fixfx1FNPoWnTpnByckJwcDD27NkjLRdCYPr06fDx8YGTkxMiIyNx+vRpi3VkZWVh+PDh0Gg0cHd3x+jRo5GXl2dRc+jQITzwwANQq9Xw9/fH7Nmzy/Vl7dq1aNeuHdRqNYKDg7Fhw4ba2WkbMJlMmDZtGoKCguDk5IR77rkHb7/9tsVvvvFY19y2bdvw6KOPwtfXFzKZDOvWrbNYbk/Htip9uSNBdmvVqlVCqVSKr776Shw9elQ899xzwt3dXaSnp9u6a3YjKipKLFmyRBw5ckQcOHBADBgwQLRo0ULk5eVJNc8//7zw9/cXSUlJYs+ePaJnz56iV69e0vLi4mLRqVMnERkZKfbv3y82bNggPD09xZQpU6Sas2fPCmdnZzFp0iRx7Ngx8cknnwiFQiE2bdok1TSmz2vXrl0iMDBQdO7cWUycOFFq57G2jqysLBEQECBGjhwpUlJSxNmzZ8XPP/8s/vzzT6nmvffeE1qtVqxbt04cPHhQDBo0SAQFBYnr169LNf379xddunQRO3fuFL///rto1aqViI2NlZYbDAbh7e0thg8fLo4cOSJWrlwpnJycxL///W+pZvv27UKhUIjZs2eLY8eOialTpwpHR0dx+PDhujkYteydd94RTZs2FevXrxepqali7dq1wtXVVXz88cdSDY91zW3YsEG88cYb4ttvvxUAxHfffWex3J6ObVX6cicMVXasR48eYvz48dJrk8kkfH19RUJCgg17Zd8yMjIEALF161YhhBDZ2dnC0dFRrF27Vqo5fvy4ACCSk5OFECX/0cvlcqHX66WahQsXCo1GIwoLC4UQQkyePFl07NjRYltDhw4VUVFR0uvG8nnl5uaK1q1bi8TERBERESGFKh5r6/nXv/4l7r///kqXm81modPpxJw5c6S27OxsoVKpxMqVK4UQQhw7dkwAELt375ZqNm7cKGQymbh48aIQQojPPvtMNGnSRDr2pdtu27at9HrIkCEiOjraYvthYWFi7Nixd7eTdiI6Olo888wzFm1PPPGEGD58uBCCx9qabg1V9nRsq9KXquDpPztlNBqxd+9eREZGSm1yuRyRkZFITk62Yc/sm8FgAAB4eHgAAPbu3YuioiKL49iuXTu0aNFCOo7JyckIDg6Gt7e3VBMVFYWcnBwcPXpUqim7jtKa0nU0ps9r/PjxiI6OLnc8eKyt54cffkBoaCgGDx4MLy8vdOvWDZ9//rm0PDU1FXq93uIYaLVahIWFWRxrd3d3hIaGSjWRkZGQy+VISUmRah588EEolUqpJioqCidPnsTVq1elmtt9HvVdr169kJSUhFOnTgEADh48iD/++AOPPPIIAB7r2mRPx7YqfakKhio7lZmZCZPJZPHlAwDe3t7Q6/U26pV9M5vNiI+Px3333YdOnToBAPR6PZRKJdzd3S1qyx5HvV5f4XEuXXa7mpycHFy/fr3RfF6rVq3Cvn37kJCQUG4Zj7X1nD17FgsXLkTr1q3x888/Y9y4cfjnP/+JZcuWAbh5rG53DPR6Pby8vCyWOzg4wMPDwyqfR0M51q+99hqGDRuGdu3awdHREd26dUN8fDyGDx8OgMe6NtnTsa1KX6rCocqVRHZu/PjxOHLkCP744w9bd6VBunDhAiZOnIjExESo1Wpbd6dBM5vNCA0NxbvvvgsA6NatG44cOYJFixYhLi7Oxr1rWNasWYPly5djxYoV6NixIw4cOID4+Hj4+vryWFO1caTKTnl6ekKhUJS7cio9PR06nc5GvbJfEyZMwPr167FlyxY0b95catfpdDAajcjOzraoL3scdTpdhce5dNntajQaDZycnBrF57V3715kZGTg3nvvhYODAxwcHLB161bMnz8fDg4O8Pb25rG2Eh8fH3To0MGirX379khLSwNw81jd7hjodDpkZGRYLC8uLkZWVpZVPo+GcqxfffVVabQqODgYTz/9NF566SVpNJbHuvbY07GtSl+qgqHKTimVSoSEhCApKUlqM5vNSEpKQnh4uA17Zl+EEJgwYQK+++47bN68GUFBQRbLQ0JC4OjoaHEcT548ibS0NOk4hoeH4/Dhwxb/4SYmJkKj0UhfbOHh4RbrKK0pXUdj+Lz69u2Lw4cP48CBA9IjNDQUw4cPl/7msbaO++67r9ytQU6dOoWAgAAAQFBQEHQ6ncUxyMnJQUpKisWxzs7Oxt69e6WazZs3w2w2IywsTKrZtm0bioqKpJrExES0bdsWTZo0kWpu93nUd9euXYNcbvlVqFAoYDabAfBY1yZ7OrZV6UuVVHlKO9W5VatWCZVKJZYuXSqOHTsmxowZI9zd3S2unGrsxo0bJ7Rarfjtt9/EpUuXpMe1a9ekmueff160aNFCbN68WezZs0eEh4eL8PBwaXnpZf79+vUTBw4cEJs2bRLNmjWr8DL/V199VRw/flwsWLCgwsv8G9vnVfbqPyF4rK1l165dwsHBQbzzzjvi9OnTYvny5cLZ2Vn873//k2ree+894e7uLr7//ntx6NAh8dhjj1V4KXq3bt1ESkqK+OOPP0Tr1q0tLkXPzs4W3t7e4umnnxZHjhwRq1atEs7OzuUuRXdwcBAffPCBOH78uJgxY0a9v8y/rLi4OOHn5yfdUuHbb78Vnp6eYvLkyVINj3XN5ebmiv3794v9+/cLAOLDDz8U+/fvF+fPnxdC2NexrUpf7oShys598sknokWLFkKpVIoePXqInTt32rpLdgVAhY8lS5ZINdevXxcvvPCCaNKkiXB2dhaPP/64uHTpksV6zp07Jx555BHh5OQkPD09xcsvvyyKioosarZs2SK6du0qlEqlaNmypcU2SjW2z+vWUMVjbT0//vij6NSpk1CpVKJdu3Zi8eLFFsvNZrOYNm2a8Pb2FiqVSvTt21ecPHnSoubKlSsiNjZWuLq6Co1GI0aNGiVyc3Mtag4ePCjuv/9+oVKphJ+fn3jvvffK9WXNmjWiTZs2QqlUio4dO4qffvrJ+jtsIzk5OWLixImiRYsWQq1Wi5YtW4o33njD4vJ8Huua27JlS4X/Gx0XFyeEsK9jW5W+3IlMiDK3jSUiIiKiGuGcKiIiIiIrYKgiIiIisgKGKiIiIiIrYKgiIiIisgKGKiIiIiIrYKgiIiIisgKGKiIiIiIrYKgiIiIisgKGKqJGYOTIkYiJibF1NyokhMCYMWPg4eEBmUyGAwcO2LpLNda7d2/Ex8dbbX0ymQzr1q2z2vpude7cuRodc6PRiFatWmHHjh2107Fb9OzZE998802dbIvobjjYugNEdHdkMtltl8+YMQMff/wx7PXHEzZt2oSlS5fit99+Q8uWLeHp6QmZTIbvvvvOboNgZb799ls4Ojrauhu1btGiRQgKCkKvXr3qZHtTp07FSy+9hMcff7zcjx8T2RP+6ySq5y5duiQ95s2bB41GY9H2yiuvQKvVwt3d3dZdrdCZM2fg4+ODXr16QafTwcHBev9fr+yv1tcFDw8PuLm51ek265oQAp9++ilGjx5dZ9t85JFHkJubi40bN9bZNolqgqGKqJ7T6XTSQ6vVQiaTWbS5urqWO/3Xu3dvvPjii4iPj0eTJk3g7e2Nzz//HPn5+Rg1ahTc3NzQqlWrcl9iR44cwSOPPAJXV1d4e3vj6aefRmZmZqV9u3LlCmJjY+Hn5wdnZ2cEBwdj5cqV0vKRI0fixRdfRFpaGmQyGQIDAxEYGAgAePzxx6W2Ut9//z3uvfdeqNVqtGzZEjNnzkRxcbG0XCaTYeHChRg0aBBcXFzwzjvvVNivwMBAzJo1CyNGjICrqysCAgLwww8/4PLly3jsscfg6uqKzp07Y8+ePVXel9LjWvb0X2BgIN59910888wzcHNzQ4sWLbB48WJpudFoxIQJE+Dj4wO1Wo2AgAAkJCRYrDMzMxOPP/44nJ2d0bp1a/zwww8Wy7du3YoePXpApVLBx8cHr732msUxMZvNmD17Nlq1agWVSoUWLVpUelxMJhOeeeYZtGvXDmlpaRXW7N27F2fOnEF0dHSV9yM7OxvPPvssmjVrBo1Ggz59+uDgwYMW6/3xxx/RvXt3qNVqeHp64vHHH5eWKRQKDBgwAKtWraqwT0R2o1o/v0xEdm3JkiVCq9WWa4+LixOPPfaY9DoiIkK4ubmJt99+W5w6dUq8/fbbQqFQiEceeUQsXrxYnDp1SowbN040bdpU5OfnCyGEuHr1qmjWrJmYMmWKOH78uNi3b594+OGHxUMPPVRpf/766y8xZ84csX//fnHmzBkxf/58oVAoREpKihBCiOzsbPHWW2+J5s2bi0uXLomMjAyRkZEhAIglS5ZIbUIIsW3bNqHRaMTSpUvFmTNnxC+//CICAwPFm2++KW0PgPDy8hJfffWVOHPmjDh//nyF/QoICBAeHh5i0aJF0r5qNBrRv39/sWbNGnHy5EkRExMj2rdvL8xmc5X2pfS4Tpw4sdx2FixYIE6fPi0SEhKEXC4XJ06cEEIIMWfOHOHv7y+2bdsmzp07J37//XexYsUKi/1p3ry5WLFihTh9+rT45z//KVxdXcWVK1ekPjk7O4sXXnhBHD9+XHz33XfC09NTzJgxQ1rH5MmTRZMmTcTSpUvFn3/+KX7//Xfx+eefCyGESE1NFQDE/v37RUFBgXj88cdFt27dpGNekQ8//FC0a9fOou1O+xEZGSkeffRRsXv3bnHq1Cnx8ssvi6ZNm0r7sX79eqFQKMT06dPFsWPHxIEDB8S7775rsY2FCxeKgICASvtFZA8YqogakOqEqvvvv196XVxcLFxcXMTTTz8ttV26dEkAEMnJyUIIId5++23Rr18/i/VeuHBBABAnT56sch+jo6PFyy+/LL3+6KOPyn1ZAhDfffedRVvfvn3LfdH+97//FT4+Phbvi4+Pv2MfAgICxFNPPSW9Lt3XadOmSW3JyckCgLh06VKV96WiUFV2O2azWXh5eYmFCxcKIYR48cUXRZ8+faTgdisAYurUqdLrvLw8AUBs3LhRCCHE66+/Ltq2bWvx/gULFghXV1dhMplETk6OUKlUUoi6VWmo+v3330Xfvn3F/fffL7KzsyvdXyGEmDhxoujTp49F2+324/fffxcajUYUFBRYtN9zzz3i3//+txBCiPDwcDF8+PDbbvf7778XcrlcmEym29YR2RInqhM1Up07d5b+VigUaNq0KYKDg6U2b29vAEBGRgYA4ODBg9iyZQtcXV3LrevMmTNo06ZNuXaTyYR3330Xa9aswcWLF2E0GlFYWAhnZ+dq9/fgwYPYvn27xakrk8mEgoICXLt2TVpnaGholdZXdv9L97Wy/dfpdDXel7LbKT01W3pMR44ciYcffhht27ZF//79MXDgQPTr16/S97u4uECj0UjvP378OMLDwy0uVrjvvvuQl5eHv/76C3q9HoWFhejbt+9t+xgbG4vmzZtj8+bNcHJyum3t9evXoVarLdputx8HDx5EXl4emjZtWm49Z86cAQAcOHAAzz333G236+TkBLPZjMLCwjv2kchWGKqIGqlbr1KTyWQWbaVf1GazGQCQl5eHRx99FO+//365dfn4+FS4jTlz5uDjjz/GvHnzEBwcDBcXF8THx8NoNFa7v3l5eZg5cyaeeOKJcsvKfsm7uLhUaX0V7evt9r+m+1LRcS5d57333ovU1FRs3LgRv/76K4YMGYLIyEh8/fXXVXr/nVQ1fAwYMAD/+9//kJycjD59+ty21tPTE4cPH7Zou91+5OXlwcfHB7/99lu5dZVePFGVfmZlZcHFxYWBiuwaQxURVcm9996Lb775BoGBgVW+Qm/79u147LHH8NRTTwEoCSinTp1Chw4dbvs+R0dHmEymcts/efIkWrVqVbMduEs13Zc70Wg0GDp0KIYOHYp//OMf6N+/P7KysuDh4XHH97Zv3x7ffPMNhBBSCNy+fTvc3NzQvHlzeHl5wcnJCUlJSXj22WcrXc+4cePQqVMnDBo0CD/99BMiIiIqre3WrRsWLlxosc3b7ce9994LvV4PBwcHi4sOyurcuTOSkpIwatSoSrd75MgRdOvW7Q5HhMi2ePUfEVXJ+PHjkZWVhdjYWOzevRtnzpzBzz//jFGjRpULQKVat26NxMRE7NixA8ePH8fYsWORnp5+x20FBgYiKSkJer0eV69eBQBMnz4d//nPfzBz5kwcPXoUx48fx6pVqzB16lSr7mdlarovt/Phhx9i5cqVOHHiBE6dOoW1a9dCp9NV+fYXL7zwAi5cuIAXX3wRJ06cwPfff48ZM2Zg0qRJkMvlUKvV+Ne//oXJkyfjP//5D86cOYOdO3fiyy+/LLeuF198EbNmzcLAgQPxxx9/VLrNhx56CHl5eTh69GiV9iMyMhLh4eGIiYnBL7/8gnPnzmHHjh144403pKsrZ8yYgZUrV2LGjBk4fvw4Dh8+XG5E9Pfffy93apTI3jBUEVGV+Pr6Yvv27TCZTOjXrx+Cg4MRHx8Pd3f3Sm/IOHXqVNx7772IiopC7969odPpqnRDz7lz5yIxMRH+/v7S6ERUVBTWr1+PX375Bd27d0fPnj3x0UcfISAgwJq7Wama7svtuLm5Yfbs2QgNDUX37t1x7tw5bNiwoco3uPTz88OGDRuwa9cudOnSBc8//zxGjx5tETSnTZuGl19+GdOnT0f79u0xdOhQaU7WreLj4zFz5kwMGDCg0rulN23aFI8//jiWL19epf2QyWTYsGEDHnzwQYwaNQpt2rTBsGHDcP78eWneWu/evbF27Vr88MMP6Nq1K/r06YNdu3ZJ67948SJ27Nhx25EsInsgE8JOb7NMRER26dChQ3j44Ydx5syZCi9csLZ//etfuHr1qsU9vojsEUeqiIioWjp37oz3338fqampdbI9Ly8vvP3223WyLaK7wZEqIiIiIivgSBURERGRFTBUEREREVkBQxURERGRFTBUEREREVkBQxURERGRFTBUEREREVkBQxURERGRFTBUEREREVkBQxURERGRFfw/fSd0vzCE/5gAAAAASUVORK5CYII=\n"
          },
          "metadata": {}
        }
      ]
    }
  ]
}